summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gemspec40
-rw-r--r--.gitignore4
-rw-r--r--.project23
-rw-r--r--.rspec4
-rw-r--r--.travis.yml25
-rw-r--r--CHANGELOG225
-rw-r--r--CONTRIBUTING.md65
-rw-r--r--Gemfile42
-rw-r--r--Modulefile4
-rw-r--r--README.markdown1234
-rw-r--r--README_DEVELOPER.markdown35
-rw-r--r--README_SPECS.markdown7
-rw-r--r--RELEASE_PROCESS.markdown19
-rw-r--r--Rakefile18
-rw-r--r--lib/facter/facter_dot_d.rb287
-rw-r--r--lib/facter/pe_version.rb53
-rw-r--r--lib/facter/puppet_vardir.rb26
-rw-r--r--lib/facter/root_home.rb4
-rw-r--r--lib/facter/util/puppet_settings.rb21
-rw-r--r--lib/puppet/parser/functions/abs.rb2
-rw-r--r--lib/puppet/parser/functions/any2array.rb33
-rw-r--r--lib/puppet/parser/functions/base64.rb37
-rw-r--r--lib/puppet/parser/functions/chomp.rb2
-rw-r--r--lib/puppet/parser/functions/chop.rb6
-rw-r--r--lib/puppet/parser/functions/concat.rb37
-rw-r--r--lib/puppet/parser/functions/count.rb22
-rw-r--r--lib/puppet/parser/functions/defined_with_params.rb35
-rw-r--r--lib/puppet/parser/functions/delete.rb30
-rw-r--r--lib/puppet/parser/functions/difference.rb36
-rw-r--r--lib/puppet/parser/functions/dirname.rb15
-rw-r--r--lib/puppet/parser/functions/ensure_packages.rb24
-rw-r--r--lib/puppet/parser/functions/ensure_resource.rb45
-rw-r--r--lib/puppet/parser/functions/flatten.rb2
-rw-r--r--lib/puppet/parser/functions/floor.rb20
-rw-r--r--lib/puppet/parser/functions/fqdn_rotate.rb46
-rw-r--r--lib/puppet/parser/functions/get_module_path.rb17
-rw-r--r--lib/puppet/parser/functions/getparam.rb35
-rw-r--r--lib/puppet/parser/functions/getvar.rb7
-rw-r--r--lib/puppet/parser/functions/has_interface_with.rb52
-rw-r--r--lib/puppet/parser/functions/has_ip_address.rb25
-rw-r--r--lib/puppet/parser/functions/has_ip_network.rb25
-rw-r--r--lib/puppet/parser/functions/has_key.rb17
-rw-r--r--lib/puppet/parser/functions/hash.rb2
-rw-r--r--lib/puppet/parser/functions/intersection.rb34
-rw-r--r--lib/puppet/parser/functions/is_domain_name.rb30
-rw-r--r--lib/puppet/parser/functions/is_float.rb2
-rw-r--r--lib/puppet/parser/functions/is_function_available.rb23
-rw-r--r--lib/puppet/parser/functions/is_integer.rb2
-rw-r--r--lib/puppet/parser/functions/is_ip_address.rb2
-rw-r--r--lib/puppet/parser/functions/is_numeric.rb2
-rw-r--r--lib/puppet/parser/functions/join_keys_to_values.rb47
-rw-r--r--lib/puppet/parser/functions/loadyaml.rb6
-rw-r--r--lib/puppet/parser/functions/max.rb21
-rw-r--r--lib/puppet/parser/functions/merge.rb12
-rw-r--r--lib/puppet/parser/functions/min.rb21
-rw-r--r--lib/puppet/parser/functions/num2bool.rb43
-rw-r--r--lib/puppet/parser/functions/parseyaml.rb2
-rw-r--r--lib/puppet/parser/functions/pick.rb29
-rw-r--r--lib/puppet/parser/functions/prefix.rb6
-rw-r--r--lib/puppet/parser/functions/range.rb9
-rw-r--r--lib/puppet/parser/functions/reject.rb31
-rw-r--r--lib/puppet/parser/functions/squeeze.rb4
-rw-r--r--lib/puppet/parser/functions/str2bool.rb7
-rw-r--r--lib/puppet/parser/functions/str2saltedsha512.rb32
-rw-r--r--lib/puppet/parser/functions/suffix.rb45
-rw-r--r--lib/puppet/parser/functions/to_bytes.rb28
-rw-r--r--lib/puppet/parser/functions/union.rb34
-rw-r--r--lib/puppet/parser/functions/uriescape.rb36
-rw-r--r--lib/puppet/parser/functions/validate_absolute_path.rb56
-rw-r--r--lib/puppet/parser/functions/validate_array.rb10
-rw-r--r--lib/puppet/parser/functions/validate_augeas.rb81
-rw-r--r--lib/puppet/parser/functions/validate_bool.rb13
-rw-r--r--lib/puppet/parser/functions/validate_cmd.rb47
-rw-r--r--lib/puppet/parser/functions/validate_hash.rb12
-rw-r--r--lib/puppet/parser/functions/validate_re.rb33
-rw-r--r--lib/puppet/parser/functions/validate_slength.rb52
-rw-r--r--lib/puppet/parser/functions/validate_string.rb12
-rw-r--r--lib/puppet/provider/file_line/ruby.rb46
-rw-r--r--lib/puppet/type/anchor.rb32
-rw-r--r--lib/puppet/type/file_line.rb50
-rw-r--r--manifests/init.pp12
-rw-r--r--manifests/stages.pp11
-rw-r--r--spec/classes/anchor_spec.rb32
-rw-r--r--spec/functions/defined_with_params_spec.rb37
-rw-r--r--spec/functions/ensure_packages_spec.rb42
-rw-r--r--spec/functions/ensure_resource_spec.rb64
-rw-r--r--spec/functions/getparam_spec.rb34
-rwxr-xr-xspec/lib/puppet_spec/files.rb53
-rwxr-xr-xspec/lib/puppet_spec/fixtures.rb28
-rw-r--r--spec/lib/puppet_spec/matchers.rb87
-rwxr-xr-xspec/lib/puppet_spec/verbose.rb9
-rwxr-xr-xspec/monkey_patches/publicize_methods.rb1
-rw-r--r--spec/spec_helper.rb99
-rw-r--r--spec/unit/facter/pe_required_facts_spec.rb69
-rw-r--r--spec/unit/facter/pe_version_spec.rb76
-rw-r--r--spec/unit/facter/root_home_spec.rb12
-rw-r--r--spec/unit/facter/util/puppet_settings_spec.rb35
-rwxr-xr-xspec/unit/puppet/parser/functions/abs_spec.rb18
-rw-r--r--spec/unit/puppet/parser/functions/any2array_spec.rb55
-rwxr-xr-xspec/unit/puppet/parser/functions/base64_spec.rb34
-rwxr-xr-xspec/unit/puppet/parser/functions/bool2num_spec.rb17
-rwxr-xr-xspec/unit/puppet/parser/functions/capitalize_spec.rb15
-rwxr-xr-xspec/unit/puppet/parser/functions/chomp_spec.rb15
-rwxr-xr-xspec/unit/puppet/parser/functions/chop_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/concat_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/count_spec.rb31
-rwxr-xr-xspec/unit/puppet/parser/functions/delete_at_spec.rb15
-rwxr-xr-xspec/unit/puppet/parser/functions/delete_spec.rb34
-rw-r--r--spec/unit/puppet/parser/functions/difference_spec.rb19
-rwxr-xr-xspec/unit/puppet/parser/functions/dirname_spec.rb24
-rwxr-xr-xspec/unit/puppet/parser/functions/downcase_spec.rb17
-rwxr-xr-xspec/unit/puppet/parser/functions/empty_spec.rb18
-rwxr-xr-xspec/unit/puppet/parser/functions/flatten_spec.rb22
-rw-r--r--spec/unit/puppet/parser/functions/floor_spec.rb39
-rw-r--r--spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb33
-rw-r--r--spec/unit/puppet/parser/functions/get_module_path_spec.rb46
-rw-r--r--spec/unit/puppet/parser/functions/getvar_spec.rb48
-rwxr-xr-xspec/unit/puppet/parser/functions/grep_spec.rb15
-rwxr-xr-xspec/unit/puppet/parser/functions/has_interface_with_spec.rb64
-rwxr-xr-xspec/unit/puppet/parser/functions/has_ip_address_spec.rb39
-rwxr-xr-xspec/unit/puppet/parser/functions/has_ip_network_spec.rb36
-rw-r--r--spec/unit/puppet/parser/functions/has_key_spec.rb50
-rw-r--r--spec/unit/puppet/parser/functions/hash_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/intersection_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/is_array_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/is_domain_name_spec.rb42
-rw-r--r--spec/unit/puppet/parser/functions/is_float_spec.rb23
-rw-r--r--spec/unit/puppet/parser/functions/is_function_available.rb31
-rw-r--r--spec/unit/puppet/parser/functions/is_hash_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/is_integer_spec.rb22
-rw-r--r--spec/unit/puppet/parser/functions/is_ip_address_spec.rb22
-rw-r--r--spec/unit/puppet/parser/functions/is_mac_address_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/is_numeric_spec.rb29
-rw-r--r--spec/unit/puppet/parser/functions/is_string_spec.rb21
-rw-r--r--spec/unit/puppet/parser/functions/join_keys_to_values_spec.rb40
-rw-r--r--spec/unit/puppet/parser/functions/join_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/keys_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/lstrip_spec.rb15
-rwxr-xr-xspec/unit/puppet/parser/functions/max_spec.rb27
-rw-r--r--spec/unit/puppet/parser/functions/member_spec.rb21
-rw-r--r--spec/unit/puppet/parser/functions/merge_spec.rb52
-rwxr-xr-xspec/unit/puppet/parser/functions/min_spec.rb27
-rw-r--r--spec/unit/puppet/parser/functions/num2bool_spec.rb62
-rw-r--r--spec/unit/puppet/parser/functions/parsejson_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/parseyaml_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/pick_spec.rb34
-rw-r--r--spec/unit/puppet/parser/functions/prefix_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/range_spec.rb38
-rwxr-xr-xspec/unit/puppet/parser/functions/reject_spec.rb20
-rw-r--r--spec/unit/puppet/parser/functions/reverse_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/rstrip_spec.rb17
-rw-r--r--spec/unit/puppet/parser/functions/shuffle_spec.rb17
-rw-r--r--spec/unit/puppet/parser/functions/size_spec.rb17
-rw-r--r--spec/unit/puppet/parser/functions/sort_spec.rb17
-rw-r--r--spec/unit/puppet/parser/functions/squeeze_spec.rb17
-rw-r--r--spec/unit/puppet/parser/functions/str2bool_spec.rb24
-rw-r--r--spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb45
-rw-r--r--spec/unit/puppet/parser/functions/strftime_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/strip_spec.rb16
-rw-r--r--spec/unit/puppet/parser/functions/suffix_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/swapcase_spec.rb15
-rw-r--r--spec/unit/puppet/parser/functions/time_spec.rb21
-rwxr-xr-xspec/unit/puppet/parser/functions/to_bytes_spec.rb58
-rw-r--r--spec/unit/puppet/parser/functions/type_spec.rb26
-rw-r--r--spec/unit/puppet/parser/functions/union_spec.rb19
-rw-r--r--spec/unit/puppet/parser/functions/unique_spec.rb17
-rw-r--r--spec/unit/puppet/parser/functions/upcase_spec.rb17
-rw-r--r--spec/unit/puppet/parser/functions/uriescape_spec.rb24
-rw-r--r--spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb83
-rw-r--r--spec/unit/puppet/parser/functions/validate_array_spec.rb39
-rw-r--r--spec/unit/puppet/parser/functions/validate_augeas_spec.rb102
-rw-r--r--spec/unit/puppet/parser/functions/validate_bool_spec.rb43
-rw-r--r--spec/unit/puppet/parser/functions/validate_cmd_spec.rb81
-rw-r--r--spec/unit/puppet/parser/functions/validate_hash_spec.rb34
-rw-r--r--spec/unit/puppet/parser/functions/validate_re_spec.rb76
-rwxr-xr-xspec/unit/puppet/parser/functions/validate_slength_spec.rb48
-rw-r--r--spec/unit/puppet/parser/functions/validate_string_spec.rb43
-rw-r--r--spec/unit/puppet/parser/functions/values_at_spec.rb23
-rw-r--r--spec/unit/puppet/parser/functions/values_spec.rb27
-rw-r--r--spec/unit/puppet/parser/functions/zip_spec.rb19
-rw-r--r--spec/unit/puppet/provider/file_line/ruby_spec.rb137
-rw-r--r--spec/unit/puppet/type/file_line_spec.rb63
-rw-r--r--tests/has_interface_with.pp10
-rw-r--r--tests/has_ip_address.pp3
-rw-r--r--tests/has_ip_network.pp4
185 files changed, 5612 insertions, 1434 deletions
diff --git a/.gemspec b/.gemspec
new file mode 100644
index 0000000..e274950
--- /dev/null
+++ b/.gemspec
@@ -0,0 +1,40 @@
+#
+# -*- encoding: utf-8 -*-
+
+Gem::Specification.new do |s|
+ s.name = "puppetmodule-stdlib"
+
+ s.version = "4.0.2"
+
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
+ s.authors = ["Puppet Labs"]
+ s.date = "2013-04-12"
+ s.description = [ 'This Gem format of the stdlib module is intended to make',
+ 'it easier for _module authors_ to resolve dependencies',
+ 'using a Gemfile when running automated testing jobs like',
+ 'Travis or Jenkins. The recommended best practice for',
+ 'installation by end users is to use the `puppet module',
+ 'install` command to install stdlib from the [Puppet',
+ 'Forge](http://forge.puppetlabs.com/puppetlabs/stdlib).' ].join(' ')
+ s.email = "puppet-dev@puppetlabs.com"
+ s.executables = []
+ s.files = [ 'CHANGELOG', 'CONTRIBUTING.md', 'Gemfile', 'LICENSE', 'Modulefile',
+ 'README.markdown', 'README_DEVELOPER.markdown', 'RELEASE_PROCESS.markdown',
+ 'Rakefile', 'spec/spec.opts' ]
+ s.files += Dir['lib/**/*.rb'] + Dir['manifests/**/*.pp'] + Dir['tests/**/*.pp'] + Dir['spec/**/*.rb']
+ s.homepage = "http://forge.puppetlabs.com/puppetlabs/stdlib"
+ s.rdoc_options = ["--title", "Puppet Standard Library Development Gem", "--main", "README.markdown", "--line-numbers"]
+ s.require_paths = ["lib"]
+ s.rubyforge_project = "puppetmodule-stdlib"
+ s.rubygems_version = "1.8.24"
+ s.summary = "This gem provides a way to make the standard library available for other module spec testing tasks."
+
+ if s.respond_to? :specification_version then
+ s.specification_version = 3
+
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
+ else
+ end
+ else
+ end
+end
diff --git a/.gitignore b/.gitignore
index 481fc81..2e3ca63 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,7 @@ pkg/
.DS_Store
metadata.json
coverage/
+spec/fixtures/
+Gemfile.lock
+.bundle/
+vendor/bundle/
diff --git a/.project b/.project
new file mode 100644
index 0000000..4e2c033
--- /dev/null
+++ b/.project
@@ -0,0 +1,23 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+ <name>stdlib</name>
+ <comment></comment>
+ <projects>
+ </projects>
+ <buildSpec>
+ <buildCommand>
+ <name>org.cloudsmith.geppetto.pp.dsl.ui.modulefileBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ <buildCommand>
+ <name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
+ <arguments>
+ </arguments>
+ </buildCommand>
+ </buildSpec>
+ <natures>
+ <nature>org.cloudsmith.geppetto.pp.dsl.ui.puppetNature</nature>
+ <nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
+ </natures>
+</projectDescription>
diff --git a/.rspec b/.rspec
new file mode 100644
index 0000000..7ab5f55
--- /dev/null
+++ b/.rspec
@@ -0,0 +1,4 @@
+--color
+--format
+progress
+--backtrace
diff --git a/.travis.yml b/.travis.yml
new file mode 100644
index 0000000..1bb1889
--- /dev/null
+++ b/.travis.yml
@@ -0,0 +1,25 @@
+language: ruby
+bundler_args: --without development
+script: "bundle exec rake spec SPEC_OPTS='--color --format documentation'"
+rvm:
+ - 1.8.7
+ - 1.9.3
+ - 2.0.0
+ - ruby-head
+env:
+ - PUPPET_GEM_VERSION=">= 3.0.0"
+matrix:
+ allow_failures:
+ - rvm: 2.0.0
+ - rvm: ruby-head
+ include:
+ - rvm: 1.8.7
+ env: PUPPET_GEM_VERSION="~> 2.7"
+notifications:
+ email: false
+ webhooks:
+ urls:
+ - https://puppet-dev-community.herokuapp.com/event/travis-ci/
+ on_success: always
+ on_failure: always
+ on_start: yes
diff --git a/CHANGELOG b/CHANGELOG
index dff036b..e1a095f 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,3 +1,228 @@
+2013-05-06 - Jeff McCune <jeff@puppetlabs.com> - 4.1.0
+ * (#20582) Restore facter_dot_d to stdlib for PE users (3b887c8)
+ * (maint) Update Gemfile with GEM_FACTER_VERSION (f44d535)
+
+2013-05-06 - Alex Cline <acline@us.ibm.com> - 4.1.0
+ * Terser method of string to array conversion courtesy of ethooz. (d38bce0)
+
+2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0
+ * Refactor ensure_resource expectations (b33cc24)
+
+2013-05-06 - Alex Cline <acline@us.ibm.com> 4.1.0
+ * Changed str-to-array conversion and removed abbreviation. (de253db)
+
+2013-05-03 - Alex Cline <acline@us.ibm.com> 4.1.0
+ * (#20548) Allow an array of resource titles to be passed into the ensure_resource function (e08734a)
+
+2013-05-02 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.1.0
+ * Add a dirname function (2ba9e47)
+
+2013-04-29 - Mark Smith-Guerrero <msmithgu@gmail.com> - 4.1.0
+ * (maint) Fix a small typo in hash() description (928036a)
+
+2013-04-12 - Jeff McCune <jeff@puppetlabs.com> - 4.0.2
+ * Update user information in gemspec to make the intent of the Gem clear.
+
+2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.1
+ * Fix README function documentation (ab3e30c)
+
+2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0
+ * stdlib 4.0 drops support with Puppet 2.7
+ * stdlib 4.0 preserves support with Puppet 3
+
+2013-04-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0
+ * Add ability to use puppet from git via bundler (9c5805f)
+
+2013-04-10 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0
+ * (maint) Make stdlib usable as a Ruby GEM (e81a45e)
+
+2013-04-10 - Erik Dalén <dalen@spotify.com> - 4.0.0
+ * Add a count function (f28550e)
+
+2013-03-31 - Amos Shapira <ashapira@atlassian.com> - 4.0.0
+ * (#19998) Implement any2array (7a2fb80)
+
+2013-03-29 - Steve Huff <shuff@vecna.org> - 4.0.0
+ * (19864) num2bool match fix (8d217f0)
+
+2013-03-20 - Erik Dalén <dalen@spotify.com> - 4.0.0
+ * Allow comparisons of Numeric and number as String (ff5dd5d)
+
+2013-03-26 - Richard Soderberg <rsoderberg@mozilla.com> - 4.0.0
+ * add suffix function to accompany the prefix function (88a93ac)
+
+2013-03-19 - Kristof Willaert <kristof.willaert@gmail.com> - 4.0.0
+ * Add floor function implementation and unit tests (0527341)
+
+2012-04-03 - Eric Shamow <eric@puppetlabs.com> - 4.0.0
+ * (#13610) Add is_function_available to stdlib (961dcab)
+
+2012-12-17 - Justin Lambert <jlambert@eml.cc> - 4.0.0
+ * str2bool should return a boolean if called with a boolean (5d5a4d4)
+
+2012-10-23 - Uwe Stuehler <ustuehler@team.mobile.de> - 4.0.0
+ * Fix number of arguments check in flatten() (e80207b)
+
+2013-03-11 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0
+ * Add contributing document (96e19d0)
+
+2013-03-04 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.0.0
+ * Add missing documentation for validate_augeas and validate_cmd to README.markdown (a1510a1)
+
+2013-02-14 - Joshua Hoblitt <jhoblitt@cpan.org> - 4.0.0
+ * (#19272) Add has_element() function (95cf3fe)
+
+2013-02-07 - Raphaël Pinson <raphael.pinson@camptocamp.com> - 4.0.0
+ * validate_cmd(): Use Puppet::Util::Execution.execute when available (69248df)
+
+2012-12-06 - Raphaël Pinson <raphink@gmail.com> - 4.0.0
+ * Add validate_augeas function (3a97c23)
+
+2012-12-06 - Raphaël Pinson <raphink@gmail.com> - 4.0.0
+ * Add validate_cmd function (6902cc5)
+
+2013-01-14 - David Schmitt <david@dasz.at> - 4.0.0
+ * Add geppetto project definition (b3fc0a3)
+
+2013-01-02 - Jaka Hudoklin <jakahudoklin@gmail.com> - 4.0.0
+ * Add getparam function to get defined resource parameters (20e0e07)
+
+2013-01-05 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0
+ * (maint) Add Travis CI Support (d082046)
+
+2012-12-04 - Jeff McCune <jeff@puppetlabs.com> - 4.0.0
+ * Clarify that stdlib 3 supports Puppet 3 (3a6085f)
+
+2012-11-30 - Erik Dalén <dalen@spotify.com> - 4.0.0
+ * maint: style guideline fixes (7742e5f)
+
+2012-11-09 - James Fryman <james@frymanet.com> - 4.0.0
+ * puppet-lint cleanup (88acc52)
+
+2012-11-06 - Joe Julian <me@joejulian.name> - 4.0.0
+ * Add function, uriescape, to URI.escape strings. Redmine #17459 (fd52b8d)
+
+2012-09-18 - Chad Metcalf <chad@wibidata.com> - 3.2.0
+ * Add an ensure_packages function. (8a8c09e)
+
+2012-11-23 - Erik Dalén <dalen@spotify.com> - 3.2.0
+ * (#17797) min() and max() functions (9954133)
+
+2012-05-23 - Peter Meier <peter.meier@immerda.ch> - 3.2.0
+ * (#14670) autorequire a file_line resource's path (dfcee63)
+
+2012-11-19 - Joshua Harlan Lifton <lifton@puppetlabs.com> - 3.2.0
+ * Add join_keys_to_values function (ee0f2b3)
+
+2012-11-17 - Joshua Harlan Lifton <lifton@puppetlabs.com> - 3.2.0
+ * Extend delete function for strings and hashes (7322e4d)
+
+2012-08-03 - Gary Larizza <gary@puppetlabs.com> - 3.2.0
+ * Add the pick() function (ba6dd13)
+
+2012-03-20 - Wil Cooley <wcooley@pdx.edu> - 3.2.0
+ * (#13974) Add predicate functions for interface facts (f819417)
+
+2012-11-06 - Joe Julian <me@joejulian.name> - 3.2.0
+ * Add function, uriescape, to URI.escape strings. Redmine #17459 (70f4a0e)
+
+2012-10-25 - Jeff McCune <jeff@puppetlabs.com> - 3.1.1
+ * (maint) Fix spec failures resulting from Facter API changes (97f836f)
+
+2012-10-23 - Matthaus Owens <matthaus@puppetlabs.com> - 3.1.0
+ * Add PE facts to stdlib (cdf3b05)
+
+2012-08-16 - Jeff McCune <jeff@puppetlabs.com> - 3.0.1
+ * Fix accidental removal of facts_dot_d.rb in 3.0.0 release
+
+2012-08-16 - Jeff McCune <jeff@puppetlabs.com> - 3.0.0
+ * stdlib 3.0 drops support with Puppet 2.6
+ * stdlib 3.0 preserves support with Puppet 2.7
+
+2012-08-07 - Dan Bode <dan@puppetlabs.com> - 3.0.0
+ * Add function ensure_resource and defined_with_params (ba789de)
+
+2012-07-10 - Hailee Kenney <hailee@puppetlabs.com> - 3.0.0
+ * (#2157) Remove facter_dot_d for compatibility with external facts (f92574f)
+
+2012-04-10 - Chris Price <chris@puppetlabs.com> - 3.0.0
+ * (#13693) moving logic from local spec_helper to puppetlabs_spec_helper (85f96df)
+
+2012-10-25 - Jeff McCune <jeff@puppetlabs.com> - 2.5.1
+ * (maint) Fix spec failures resulting from Facter API changes (97f836f)
+
+2012-10-23 - Matthaus Owens <matthaus@puppetlabs.com> - 2.5.0
+ * Add PE facts to stdlib (cdf3b05)
+
+2012-08-15 - Dan Bode <dan@puppetlabs.com> - 2.5.0
+ * Explicitly load functions used by ensure_resource (9fc3063)
+
+2012-08-13 - Dan Bode <dan@puppetlabs.com> - 2.5.0
+ * Add better docs about duplicate resource failures (97d327a)
+
+2012-08-13 - Dan Bode <dan@puppetlabs.com> - 2.5.0
+ * Handle undef for parameter argument (4f8b133)
+
+2012-08-07 - Dan Bode <dan@puppetlabs.com> - 2.5.0
+ * Add function ensure_resource and defined_with_params (a0cb8cd)
+
+2012-08-20 - Jeff McCune <jeff@puppetlabs.com> - 2.5.0
+ * Disable tests that fail on 2.6.x due to #15912 (c81496e)
+
+2012-08-20 - Jeff McCune <jeff@puppetlabs.com> - 2.5.0
+ * (Maint) Fix mis-use of rvalue functions as statements (4492913)
+
+2012-08-20 - Jeff McCune <jeff@puppetlabs.com> - 2.5.0
+ * Add .rspec file to repo root (88789e8)
+
+2012-06-07 - Chris Price <chris@puppetlabs.com> - 2.4.0
+ * Add support for a 'match' parameter to file_line (a06c0d8)
+
+2012-08-07 - Erik Dalén <dalen@spotify.com> - 2.4.0
+ * (#15872) Add to_bytes function (247b69c)
+
+2012-07-19 - Jeff McCune <jeff@puppetlabs.com> - 2.4.0
+ * (Maint) use PuppetlabsSpec::PuppetInternals.scope (master) (deafe88)
+
+2012-07-10 - Hailee Kenney <hailee@puppetlabs.com> - 2.4.0
+ * (#2157) Make facts_dot_d compatible with external facts (5fb0ddc)
+
+2012-03-16 - Steve Traylen <steve.traylen@cern.ch> - 2.4.0
+ * (#13205) Rotate array/string randomley based on fqdn, fqdn_rotate() (fef247b)
+
+2012-05-22 - Peter Meier <peter.meier@immerda.ch> - 2.3.3
+ * fix regression in #11017 properly (f0a62c7)
+
+2012-05-10 - Jeff McCune <jeff@puppetlabs.com> - 2.3.3
+ * Fix spec tests using the new spec_helper (7d34333)
+
+2012-05-10 - Puppet Labs <support@puppetlabs.com> - 2.3.2
+ * Make file_line default to ensure => present (1373e70)
+ * Memoize file_line spec instance variables (20aacc5)
+ * Fix spec tests using the new spec_helper (1ebfa5d)
+ * (#13595) initialize_everything_for_tests couples modules Puppet ver (3222f35)
+ * (#13439) Fix MRI 1.9 issue with spec_helper (15c5fd1)
+ * (#13439) Fix test failures with Puppet 2.6.x (665610b)
+ * (#13439) refactor spec helper for compatibility with both puppet 2.7 and master (82194ca)
+ * (#13494) Specify the behavior of zero padded strings (61891bb)
+
+2012-03-29 Puppet Labs <support@puppetlabs.com> - 2.1.3
+* (#11607) Add Rakefile to enable spec testing
+* (#12377) Avoid infinite loop when retrying require json
+
+2012-03-13 Puppet Labs <support@puppetlabs.com> - 2.3.1
+* (#13091) Fix LoadError bug with puppet apply and puppet_vardir fact
+
+2012-03-12 Puppet Labs <support@puppetlabs.com> - 2.3.0
+* Add a large number of new Puppet functions
+* Backwards compatibility preserved with 2.2.x
+
+2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.2.1
+* Documentation only release for the Forge
+
+2011-12-30 Puppet Labs <support@puppetlabs.com> - 2.1.2
+* Documentation only release for PE 2.0.x
+
2011-11-08 Puppet Labs <support@puppetlabs.com> - 2.2.0
* #10285 - Refactor json to use pson instead.
* Maint - Add watchr autotest script
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644
index 0000000..bd11f63
--- /dev/null
+++ b/CONTRIBUTING.md
@@ -0,0 +1,65 @@
+# How to contribute
+
+Third-party patches are essential for keeping stdlib great. We simply can't
+access the huge number of platforms and myriad configurations for running
+stdlib. We want to keep it as easy as possible to contribute changes that
+get things working in your environment. There are a few guidelines that we
+need contributors to follow so that we can have a chance of keeping on
+top of things.
+
+## Getting Started
+
+* Make sure you have a [Redmine account](http://projects.puppetlabs.com)
+* Make sure you have a [GitHub account](https://github.com/signup/free)
+* Submit a ticket for your issue, assuming one does not already exist.
+ * Clearly describe the issue including steps to reproduce when it is a bug.
+ * Make sure you fill in the earliest version that you know has the issue.
+* Fork the repository on GitHub
+
+## Making Changes
+
+* Create a topic branch from where you want to base your work.
+ * This is usually the master branch.
+ * Only target release branches if you are certain your fix must be on that
+ branch.
+ * To quickly create a topic branch based on master; `git branch
+ fix/master/my_contribution master` then checkout the new branch with `git
+ checkout fix/master/my_contribution`. Please avoid working directly on the
+ `master` branch.
+* Make commits of logical units.
+* Check for unnecessary whitespace with `git diff --check` before committing.
+* Make sure your commit messages are in the proper format.
+
+````
+ (#99999) Make the example in CONTRIBUTING imperative and concrete
+
+ Without this patch applied the example commit message in the CONTRIBUTING
+ document is not a concrete example. This is a problem because the
+ contributor is left to imagine what the commit message should look like
+ based on a description rather than an example. This patch fixes the
+ problem by making the example concrete and imperative.
+
+ The first line is a real life imperative statement with a ticket number
+ from our issue tracker. The body describes the behavior without the patch,
+ why this is a problem, and how the patch fixes the problem when applied.
+````
+
+* Make sure you have added the necessary tests for your changes.
+* Run _all_ the tests to assure nothing else was accidentally broken.
+
+## Submitting Changes
+
+* Sign the [Contributor License Agreement](http://links.puppetlabs.com/cla).
+* Push your changes to a topic branch in your fork of the repository.
+* Submit a pull request to the repository in the puppetlabs organization.
+* Update your Redmine ticket to mark that you have submitted code and are ready for it to be reviewed.
+ * Include a link to the pull request in the ticket
+
+# Additional Resources
+
+* [More information on contributing](http://links.puppetlabs.com/contribute-to-puppet)
+* [Bug tracker (Redmine)](http://projects.puppetlabs.com)
+* [Contributor License Agreement](http://links.puppetlabs.com/cla)
+* [General GitHub documentation](http://help.github.com/)
+* [GitHub pull request documentation](http://help.github.com/send-pull-requests/)
+* #puppet-dev IRC channel on freenode.org
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..197cc6b
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,42 @@
+source "https://rubygems.org"
+
+def location_for(place, fake_version = nil)
+ mdata = /^(git:[^#]*)#(.*)/.match(place)
+ if mdata
+ [fake_version, { :git => mdata[1], :branch => mdata[2], :require => false }].compact
+ elsif place =~ /^file:\/\/(.*)/
+ ['>= 0', { :path => File.expand_path(mdata[1]), :require => false }]
+ else
+ [place, { :require => false }]
+ end
+end
+
+group :development do
+ gem 'watchr'
+end
+
+group :development, :test do
+ gem 'rake'
+ gem 'puppetmodule-stdlib', ">= 1.0.0", :path => File.expand_path("..", __FILE__)
+ gem 'rspec', "~> 2.11.0", :require => false
+ gem 'mocha', "~> 0.10.5", :require => false
+ gem 'puppetlabs_spec_helper', :require => false
+ gem 'rspec-puppet', :require => false
+end
+
+facterversion = ENV['GEM_FACTER_VERSION']
+if facterversion
+ gem 'facter', *location_for(facterversion)
+else
+ gem 'facter', :require => false
+end
+
+ENV['GEM_PUPPET_VERSION'] ||= ENV['PUPPET_GEM_VERSION']
+puppetversion = ENV['GEM_PUPPET_VERSION']
+if puppetversion
+ gem 'puppet', *location_for(puppetversion)
+else
+ gem 'puppet', :require => false
+end
+
+# vim:ft=ruby
diff --git a/Modulefile b/Modulefile
index 20ddad2..9d2e8c2 100644
--- a/Modulefile
+++ b/Modulefile
@@ -1,6 +1,6 @@
name 'puppetlabs-stdlib'
-version '2.2.0'
-source 'git://github.com/puppetlabs/puppetlabs-stdlib'
+version '4.1.0'
+source 'git://github.com/puppetlabs/puppetlabs-stdlib.git'
author 'puppetlabs'
license 'Apache 2.0'
summary 'Puppet Module Standard Library'
diff --git a/README.markdown b/README.markdown
index 4f06651..0e40f51 100644
--- a/README.markdown
+++ b/README.markdown
@@ -1,5 +1,7 @@
# Puppet Labs Standard Library #
+[![Build Status](https://travis-ci.org/puppetlabs/puppetlabs-stdlib.png?branch=master)](https://travis-ci.org/puppetlabs/puppetlabs-stdlib)
+
This module provides a "standard library" of resources for developing Puppet
Modules. This modules will include the following additions to Puppet
@@ -14,47 +16,1221 @@ This module is officially curated and provided by Puppet Labs. The modules
Puppet Labs writes and distributes will make heavy use of this standard
library.
+To report or research a bug with any part of this module, please go to
+[http://projects.puppetlabs.com/projects/stdlib](http://projects.puppetlabs.com/projects/stdlib)
+
+# Versions #
+
+This module follows semver.org (v1.0.0) versioning guidelines. The standard
+library module is released as part of [Puppet
+Enterprise](http://puppetlabs.com/puppet/puppet-enterprise/) and as a result
+older versions of Puppet Enterprise that Puppet Labs still supports will have
+bugfix maintenance branches periodically "merged up" into master. The current
+list of integration branches are:
+
+ * v2.1.x (v2.1.1 released in PE 1)
+ * v2.2.x (Never released as part of PE, only to the Forge)
+ * v2.3.x (Released in PE 2)
+ * v3.0.x (Never released as part of PE, only to the Forge)
+ * v4.0.x (Drops support for Puppet 2.7)
+ * master (mainline development branch)
+
+The first Puppet Enterprise version including the stdlib module is Puppet
+Enterprise 1.2.
+
# Compatibility #
-This module is designed to work with Puppet version 2.6 and later. It may be
-forked if Puppet 2.7 specific features are added. There are currently no plans
-for a Puppet 0.25 standard library module.
+Puppet Versions | < 2.6 | 2.6 | 2.7 | 3.x |
+:---------------|:-----:|:---:|:---:|:----:
+**stdlib 2.x** | no | **yes** | **yes** | no
+**stdlib 3.x** | no | no | **yes** | **yes**
+**stdlib 4.x** | no | no | no | **yes**
+
+The stdlib module does not work with Puppet versions released prior to Puppet
+2.6.0.
+
+## stdlib 2.x ##
+
+All stdlib releases in the 2.0 major version support Puppet 2.6 and Puppet 2.7.
+
+## stdlib 3.x ##
+
+The 3.0 major release of stdlib drops support for Puppet 2.6. Stdlib 3.x
+supports Puppet 2 and Puppet 3.
+
+## stdlib 4.x ##
+
+The 4.0 major release of stdlib drops support for Puppet 2.7. Stdlib 4.x
+supports Puppet 3. Notably, ruby 1.8.5 is no longer supported though ruby
+1.8.7, 1.9.3, and 2.0.0 are fully supported.
# Functions #
- Please see `puppet doc -r function` for documentation on each function. The
- current list of functions is:
+abs
+---
+Returns the absolute value of a number, for example -34.56 becomes
+34.56. Takes a single integer and float value as an argument.
+
+
+- *Type*: rvalue
+
+any2array
+---------
+This converts any object to an array containing that object. Empty argument
+lists are converted to an empty array. Arrays are left untouched. Hashes are
+converted to arrays of alternating keys and values.
+
+
+- *Type*: rvalue
+
+base64
+--------
+Converts a string to and from base64 encoding.
+Requires an action ['encode','decode'] and either a plain or base64 encoded
+string
+
+
+- *Type*: rvalue
+
+bool2num
+--------
+Converts a boolean to a number. Converts the values:
+false, f, 0, n, and no to 0
+true, t, 1, y, and yes to 1
+ Requires a single boolean or string as an input.
+
+
+- *Type*: rvalue
+
+capitalize
+----------
+Capitalizes the first letter of a string or array of strings.
+Requires either a single string or an array as an input.
+
+
+- *Type*: rvalue
+
+chomp
+-----
+Removes the record separator from the end of a string or an array of
+strings, for example `hello\n` becomes `hello`.
+Requires a single string or array as an input.
+
+
+- *Type*: rvalue
+
+chop
+----
+Returns a new string with the last character removed. If the string ends
+with `\r\n`, both characters are removed. Applying chop to an empty
+string returns an empty string. If you wish to merely remove record
+separators then you should use the `chomp` function.
+Requires a string or array of strings as input.
+
+
+- *Type*: rvalue
+
+concat
+------
+Appends the contents of array 2 onto array 1.
+
+*Example:*
+
+ concat(['1','2','3'],['4','5','6'])
+
+Would result in:
+
+ ['1','2','3','4','5','6']
+
+
+- *Type*: rvalue
+
+count
+-----
+Takes an array as first argument and an optional second argument.
+Count the number of elements in array that matches second argument.
+If called with only an array it counts the number of elements that are not nil/undef.
+
+
+- *Type*: rvalue
+
+defined_with_params
+-------------------
+Takes a resource reference and an optional hash of attributes.
+
+Returns true if a resource with the specified attributes has already been added
+to the catalog, and false otherwise.
+
+ user { 'dan':
+ ensure => present,
+ }
+
+ if ! defined_with_params(User[dan], {'ensure' => 'present' }) {
+ user { 'dan': ensure => present, }
+ }
+
+
+- *Type*: rvalue
+
+delete
+------
+Deletes all instances of a given element from an array, substring from a
+string, or key from a hash.
+
+*Examples:*
+
+ delete(['a','b','c','b'], 'b')
+ Would return: ['a','c']
+
+ delete({'a'=>1,'b'=>2,'c'=>3}, 'b')
+ Would return: {'a'=>1,'c'=>3}
+
+ delete('abracadabra', 'bra')
+ Would return: 'acada'
+
+
+- *Type*: rvalue
+
+delete_at
+---------
+Deletes a determined indexed value from an array.
+
+*Examples:*
+
+ delete_at(['a','b','c'], 1)
+
+Would return: ['a','c']
+
+
+- *Type*: rvalue
+
+difference
+----------
+This function returns the difference between two arrays.
+The returned array is a copy of the original array, removing any items that
+also appear in the second array.
+
+*Examples:*
+
+ difference(["a","b","c"],["b","c","d"])
+
+Would return: ["a"]
+
+dirname
+-------
+Returns the `dirname` of a path.
+
+*Examples:*
+
+ dirname('/path/to/a/file.ext')
+
+Would return: '/path/to/a'
+
+downcase
+--------
+Converts the case of a string or all strings in an array to lower case.
+
+
+- *Type*: rvalue
+
+empty
+-----
+Returns true if the variable is empty.
+
+
+- *Type*: rvalue
+
+ensure_packages
+---------------
+Takes a list of packages and only installs them if they don't already exist.
+
+
+- *Type*: statement
+
+ensure_resource
+---------------
+Takes a resource type, title, and a list of attributes that describe a
+resource.
+
+ user { 'dan':
+ ensure => present,
+ }
+
+This example only creates the resource if it does not already exist:
+
+ ensure_resource('user, 'dan', {'ensure' => 'present' })
+
+If the resource already exists but does not match the specified parameters,
+this function will attempt to recreate the resource leading to a duplicate
+resource definition error.
+
+An array of resources can also be passed in and each will be created with
+the type and parameters specified if it doesn't already exist.
+
+ ensure_resource('user', ['dan','alex'], {'ensure' => 'present'})
+
+
+
+- *Type*: statement
+
+flatten
+-------
+This function flattens any deeply nested arrays and returns a single flat array
+as a result.
+
+*Examples:*
+
+ flatten(['a', ['b', ['c']]])
+
+Would return: ['a','b','c']
+
+
+- *Type*: rvalue
+
+floor
+-----
+Returns the largest integer less or equal to the argument.
+Takes a single numeric value as an argument.
+
+
+- *Type*: rvalue
+
+fqdn_rotate
+-----------
+Rotates an array a random number of times based on a nodes fqdn.
+
+
+- *Type*: rvalue
+
+get_module_path
+---------------
+Returns the absolute path of the specified module for the current
+environment.
+
+Example:
+ $module_path = get_module_path('stdlib')
+
+
+- *Type*: rvalue
+
+getparam
+--------
+Takes a resource reference and name of the parameter and
+returns value of resource's parameter.
+
+*Examples:*
+
+ define example_resource($param) {
+ }
+
+ example_resource { "example_resource_instance":
+ param => "param_value"
+ }
+
+ getparam(Example_resource["example_resource_instance"], "param")
+
+Would return: param_value
+
+
+- *Type*: rvalue
+
+getvar
+------
+Lookup a variable in a remote namespace.
+
+For example:
+
+ $foo = getvar('site::data::foo')
+ # Equivalent to $foo = $site::data::foo
+
+This is useful if the namespace itself is stored in a string:
+
+ $datalocation = 'site::data'
+ $bar = getvar("${datalocation}::bar")
+ # Equivalent to $bar = $site::data::bar
+
+
+- *Type*: rvalue
+
+grep
+----
+This function searches through an array and returns any elements that match
+the provided regular expression.
+
+*Examples:*
+
+ grep(['aaa','bbb','ccc','aaaddd'], 'aaa')
+
+Would return:
+
+ ['aaa','aaaddd']
+
+
+- *Type*: rvalue
+
+has_interface_with
+------------------
+Returns boolean based on kind and value:
+* macaddress
+* netmask
+* ipaddress
+* network
+
+has_interface_with("macaddress", "x:x:x:x:x:x")
+has_interface_with("ipaddress", "127.0.0.1") => true
+etc.
+
+If no "kind" is given, then the presence of the interface is checked:
+has_interface_with("lo") => true
+
+
+- *Type*: rvalue
+
+has_ip_address
+--------------
+Returns true if the client has the requested IP address on some interface.
+
+This function iterates through the 'interfaces' fact and checks the
+'ipaddress_IFACE' facts, performing a simple string comparison.
+
+
+- *Type*: rvalue
+
+has_ip_network
+--------------
+Returns true if the client has an IP address within the requested network.
+
+This function iterates through the 'interfaces' fact and checks the
+'network_IFACE' facts, performing a simple string comparision.
+
+
+- *Type*: rvalue
+
+has_key
+-------
+Determine if a hash has a certain key value.
+
+Example:
+
+ $my_hash = {'key_one' => 'value_one'}
+ if has_key($my_hash, 'key_two') {
+ notice('we will not reach here')
+ }
+ if has_key($my_hash, 'key_one') {
+ notice('this will be printed')
+ }
+
+
+
+- *Type*: rvalue
+
+hash
+----
+This function converts an array into a hash.
+
+*Examples:*
+
+ hash(['a',1,'b',2,'c',3])
+
+Would return: {'a'=>1,'b'=>2,'c'=>3}
+
+
+- *Type*: rvalue
+
+intersection
+-----------
+This function returns an array an intersection of two.
+
+*Examples:*
+
+ intersection(["a","b","c"],["b","c","d"])
+
+Would return: ["b","c"]
+
+is_array
+--------
+Returns true if the variable passed to this function is an array.
+
+- *Type*: rvalue
+
+is_domain_name
+--------------
+Returns true if the string passed to this function is a syntactically correct domain name.
+
+- *Type*: rvalue
+
+is_float
+--------
+Returns true if the variable passed to this function is a float.
+
+- *Type*: rvalue
+
+is_function_available
+---------------------
+This function accepts a string as an argument, determines whether the
+Puppet runtime has access to a function by that name. It returns a
+true if the function exists, false if not.
+
+- *Type*: rvalue
+
+is_hash
+-------
+Returns true if the variable passed to this function is a hash.
+
+- *Type*: rvalue
+
+is_integer
+----------
+Returns true if the variable returned to this string is an integer.
+
+- *Type*: rvalue
+
+is_ip_address
+-------------
+Returns true if the string passed to this function is a valid IP address.
+
+- *Type*: rvalue
+
+is_mac_address
+--------------
+Returns true if the string passed to this function is a valid mac address.
+
+- *Type*: rvalue
+
+is_numeric
+----------
+Returns true if the variable passed to this function is a number.
+
+- *Type*: rvalue
+
+is_string
+---------
+Returns true if the variable passed to this function is a string.
+
+- *Type*: rvalue
+
+join
+----
+This function joins an array into a string using a seperator.
+
+*Examples:*
+
+ join(['a','b','c'], ",")
+
+Would result in: "a,b,c"
+
+- *Type*: rvalue
+
+join_keys_to_values
+-------------------
+This function joins each key of a hash to that key's corresponding value with a
+separator. Keys and values are cast to strings. The return value is an array in
+which each element is one joined key/value pair.
+
+*Examples:*
+
+ join_keys_to_values({'a'=>1,'b'=>2}, " is ")
+
+Would result in: ["a is 1","b is 2"]
+
+- *Type*: rvalue
+
+keys
+----
+Returns the keys of a hash as an array.
+
+- *Type*: rvalue
+
+loadyaml
+--------
+Load a YAML file containing an array, string, or hash, and return the data
+in the corresponding native data type.
+
+For example:
+
+ $myhash = loadyaml('/etc/puppet/data/myhash.yaml')
+
+
+- *Type*: rvalue
+
+lstrip
+------
+Strips leading spaces to the left of a string.
+
+- *Type*: rvalue
+
+max
+---
+Returns the highest value of all arguments.
+Requires at least one argument.
+
+- *Type*: rvalue
+
+member
+------
+This function determines if a variable is a member of an array.
+
+*Examples:*
+
+ member(['a','b'], 'b')
+
+Would return: true
+
+ member(['a','b'], 'c')
+
+Would return: false
+
+- *Type*: rvalue
+
+merge
+-----
+Merges two or more hashes together and returns the resulting hash.
+
+For example:
+
+ $hash1 = {'one' => 1, 'two', => 2}
+ $hash2 = {'two' => 'dos', 'three', => 'tres'}
+ $merged_hash = merge($hash1, $hash2)
+ # The resulting hash is equivalent to:
+ # $merged_hash = {'one' => 1, 'two' => 'dos', 'three' => 'tres'}
+
+When there is a duplicate key, the key in the rightmost hash will "win."
+
+- *Type*: rvalue
+
+min
+---
+Returns the lowest value of all arguments.
+Requires at least one argument.
+
+- *Type*: rvalue
+
+num2bool
+--------
+This function converts a number or a string representation of a number into a
+true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0
+become true.
+
+- *Type*: rvalue
+
+parsejson
+---------
+This function accepts JSON as a string and converts into the correct Puppet
+structure.
+
+- *Type*: rvalue
+
+parseyaml
+---------
+This function accepts YAML as a string and converts it into the correct
+Puppet structure.
+
+- *Type*: rvalue
+
+pick
+----
+This function is similar to a coalesce function in SQL in that it will return
+the first value in a list of values that is not undefined or an empty string
+(two things in Puppet that will return a boolean false value). Typically,
+this function is used to check for a value in the Puppet Dashboard/Enterprise
+Console, and failover to a default value like the following:
+
+ $real_jenkins_version = pick($::jenkins_version, '1.449')
+
+The value of $real_jenkins_version will first look for a top-scope variable
+called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
+Enterprise Console are brought into Puppet as top-scope variables), and,
+failing that, will use a default value of 1.449.
+
+- *Type*: rvalue
+
+prefix
+------
+This function applies a prefix to all elements in an array.
+
+*Examples:*
+
+ prefix(['a','b','c'], 'p')
+
+Will return: ['pa','pb','pc']
+
+- *Type*: rvalue
+
+range
+-----
+When given range in the form of (start, stop) it will extrapolate a range as
+an array.
+
+*Examples:*
+
+ range("0", "9")
+
+Will return: [0,1,2,3,4,5,6,7,8,9]
+
+ range("00", "09")
+
+Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to
+integers automatically)
+
+ range("a", "c")
+
+Will return: ["a","b","c"]
+
+ range("host01", "host10")
+
+Will return: ["host01", "host02", ..., "host09", "host10"]
+
+- *Type*: rvalue
+
+reject
+------
+This function searches through an array and rejects all elements that match
+the provided regular expression.
+
+*Examples:*
+
+ reject(['aaa','bbb','ccc','aaaddd'], 'aaa')
+
+Would return:
+
+ ['bbb','ccc']
+
+
+- *Type*: rvalue
+
+reverse
+-------
+Reverses the order of a string or array.
+
+- *Type*: rvalue
+
+rstrip
+------
+Strips leading spaces to the right of the string.
+
+- *Type*: rvalue
+
+shuffle
+-------
+Randomizes the order of a string or array elements.
+
+- *Type*: rvalue
+
+size
+----
+Returns the number of elements in a string or array.
+
+- *Type*: rvalue
+
+sort
+----
+Sorts strings and arrays lexically.
+
+- *Type*: rvalue
+
+squeeze
+-------
+Returns a new string where runs of the same character that occur in this set
+are replaced by a single character.
+
+- *Type*: rvalue
+
+str2bool
+--------
+This converts a string to a boolean. This attempt to convert strings that
+contain things like: y, 1, t, true to 'true' and strings that contain things
+like: 0, f, n, false, no to 'false'.
+
+
+- *Type*: rvalue
+
+str2saltedsha512
+----------------
+This converts a string to a salted-SHA512 password hash (which is used for
+OS X versions >= 10.7). Given any simple string, you will get a hex version
+of a salted-SHA512 password hash that can be inserted into your Puppet
+manifests as a valid password attribute.
+
+
+- *Type*: rvalue
+
+strftime
+--------
+This function returns formatted time.
+
+*Examples:*
+
+To return the time since epoch:
+
+ strftime("%s")
+
+To return the date:
+
+ strftime("%Y-%m-%d")
+
+*Format meaning:*
+
+ %a - The abbreviated weekday name (``Sun'')
+ %A - The full weekday name (``Sunday'')
+ %b - The abbreviated month name (``Jan'')
+ %B - The full month name (``January'')
+ %c - The preferred local date and time representation
+ %C - Century (20 in 2009)
+ %d - Day of the month (01..31)
+ %D - Date (%m/%d/%y)
+ %e - Day of the month, blank-padded ( 1..31)
+ %F - Equivalent to %Y-%m-%d (the ISO 8601 date format)
+ %h - Equivalent to %b
+ %H - Hour of the day, 24-hour clock (00..23)
+ %I - Hour of the day, 12-hour clock (01..12)
+ %j - Day of the year (001..366)
+ %k - hour, 24-hour clock, blank-padded ( 0..23)
+ %l - hour, 12-hour clock, blank-padded ( 0..12)
+ %L - Millisecond of the second (000..999)
+ %m - Month of the year (01..12)
+ %M - Minute of the hour (00..59)
+ %n - Newline (
+)
+ %N - Fractional seconds digits, default is 9 digits (nanosecond)
+ %3N millisecond (3 digits)
+ %6N microsecond (6 digits)
+ %9N nanosecond (9 digits)
+ %p - Meridian indicator (``AM'' or ``PM'')
+ %P - Meridian indicator (``am'' or ``pm'')
+ %r - time, 12-hour (same as %I:%M:%S %p)
+ %R - time, 24-hour (%H:%M)
+ %s - Number of seconds since 1970-01-01 00:00:00 UTC.
+ %S - Second of the minute (00..60)
+ %t - Tab character ( )
+ %T - time, 24-hour (%H:%M:%S)
+ %u - Day of the week as a decimal, Monday being 1. (1..7)
+ %U - Week number of the current year,
+ starting with the first Sunday as the first
+ day of the first week (00..53)
+ %v - VMS date (%e-%b-%Y)
+ %V - Week number of year according to ISO 8601 (01..53)
+ %W - Week number of the current year,
+ starting with the first Monday as the first
+ day of the first week (00..53)
+ %w - Day of the week (Sunday is 0, 0..6)
+ %x - Preferred representation for the date alone, no time
+ %X - Preferred representation for the time alone, no date
+ %y - Year without a century (00..99)
+ %Y - Year with century
+ %z - Time zone as hour offset from UTC (e.g. +0900)
+ %Z - Time zone name
+ %% - Literal ``%'' character
+
+
+- *Type*: rvalue
+
+strip
+-----
+This function removes leading and trailing whitespace from a string or from
+every string inside an array.
+
+*Examples:*
+
+ strip(" aaa ")
+
+Would result in: "aaa"
+
+
+- *Type*: rvalue
+
+suffix
+------
+This function applies a suffix to all elements in an array.
+
+*Examples:*
+
+ suffix(['a','b','c'], 'p')
+
+Will return: ['ap','bp','cp']
+
+
+- *Type*: rvalue
+
+swapcase
+--------
+This function will swap the existing case of a string.
+
+*Examples:*
+
+ swapcase("aBcD")
+
+Would result in: "AbCd"
+
+
+- *Type*: rvalue
+
+time
+----
+This function will return the current time since epoch as an integer.
+
+*Examples:*
+
+ time()
+
+Will return something like: 1311972653
+
+
+- *Type*: rvalue
+
+to_bytes
+--------
+Converts the argument into bytes, for example 4 kB becomes 4096.
+Takes a single string value as an argument.
+
+
+- *Type*: rvalue
+
+type
+----
+Returns the type when passed a variable. Type can be one of:
+
+* string
+* array
+* hash
+* float
+* integer
+* boolean
+
+
+- *Type*: rvalue
+
+union
+-----
+This function returns a union of two arrays.
+
+*Examples:*
+
+ union(["a","b","c"],["b","c","d"])
+
+Would return: ["a","b","c","d"]
+
+
+unique
+------
+This function will remove duplicates from strings and arrays.
+
+*Examples:*
+
+ unique("aabbcc")
+
+Will return:
+
+ abc
+
+You can also use this with arrays:
+
+ unique(["a","a","b","b","c","c"])
+
+This returns:
+
+ ["a","b","c"]
+
+
+- *Type*: rvalue
+
+upcase
+------
+Converts a string or an array of strings to uppercase.
+
+*Examples:*
+
+ upcase("abcd")
+
+Will return:
+
+ ABCD
+
+
+- *Type*: rvalue
+
+uriescape
+---------
+Urlencodes a string or array of strings.
+Requires either a single string or an array as an input.
+
+
+- *Type*: rvalue
+
+validate_absolute_path
+----------------------
+Validate the string represents an absolute path in the filesystem. This function works
+for windows and unix style paths.
+
+The following values will pass:
+
+ $my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
+ validate_absolute_path($my_path)
+ $my_path2 = "/var/lib/puppet"
+ validate_absolute_path($my_path2)
+
+
+The following values will fail, causing compilation to abort:
+
+ validate_absolute_path(true)
+ validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
+ validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
+ $undefined = undef
+ validate_absolute_path($undefined)
+
+
+
+- *Type*: statement
+
+validate_array
+--------------
+Validate that all passed values are array data structures. Abort catalog
+compilation if any value fails this check.
+
+The following values will pass:
+
+ $my_array = [ 'one', 'two' ]
+ validate_array($my_array)
+
+The following values will fail, causing compilation to abort:
+
+ validate_array(true)
+ validate_array('some_string')
+ $undefined = undef
+ validate_array($undefined)
+
+
+
+- *Type*: statement
+
+validate_augeas
+---------------
+Perform validation of a string using an Augeas lens
+The first argument of this function should be a string to
+test, and the second argument should be the name of the Augeas lens to use.
+If Augeas fails to parse the string with the lens, the compilation will
+abort with a parse error.
+
+A third argument can be specified, listing paths which should
+not be found in the file. The `$file` variable points to the location
+of the temporary file being tested in the Augeas tree.
+
+For example, if you want to make sure your passwd content never contains
+a user `foo`, you could write:
+
+ validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo'])
+
+Or if you wanted to ensure that no users used the '/bin/barsh' shell,
+you could use:
+
+ validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]']
+
+If a fourth argument is specified, this will be the error message raised and
+seen by the user.
+
+A helpful error message can be returned like this:
+
+ validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas')
+
+
+
+- *Type*: statement
+
+validate_bool
+-------------
+Validate that all passed values are either true or false. Abort catalog
+compilation if any value fails this check.
+
+The following values will pass:
+
+ $iamtrue = true
+ validate_bool(true)
+ validate_bool(true, true, false, $iamtrue)
+
+The following values will fail, causing compilation to abort:
+
+ $some_array = [ true ]
+ validate_bool("false")
+ validate_bool("true")
+ validate_bool($some_array)
+
+
+
+- *Type*: statement
+
+validate_cmd
+------------
+Perform validation of a string with an external command.
+The first argument of this function should be a string to
+test, and the second argument should be a path to a test command
+taking a file as last argument. If the command, launched against
+a tempfile containing the passed string, returns a non-null value,
+compilation will abort with a parse error.
+
+If a third argument is specified, this will be the error message raised and
+seen by the user.
+
+A helpful error message can be returned like this:
+
+Example:
+
+ validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content')
+
+
+
+- *Type*: statement
+
+validate_hash
+-------------
+Validate that all passed values are hash data structures. Abort catalog
+compilation if any value fails this check.
+
+The following values will pass:
+
+ $my_hash = { 'one' => 'two' }
+ validate_hash($my_hash)
+
+The following values will fail, causing compilation to abort:
+
+ validate_hash(true)
+ validate_hash('some_string')
+ $undefined = undef
+ validate_hash($undefined)
+
+
+
+- *Type*: statement
+
+validate_re
+-----------
+Perform simple validation of a string against one or more regular
+expressions. The first argument of this function should be a string to
+test, and the second argument should be a stringified regular expression
+(without the // delimiters) or an array of regular expressions. If none
+of the regular expressions match the string passed in, compilation will
+abort with a parse error.
+
+If a third argument is specified, this will be the error message raised and
+seen by the user.
+
+The following strings will validate against the regular expressions:
+
+ validate_re('one', '^one$')
+ validate_re('one', [ '^one', '^two' ])
+
+The following strings will fail to validate, causing compilation to abort:
+
+ validate_re('one', [ '^two', '^three' ])
+
+A helpful error message can be returned like this:
+
+ validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
+
+
+
+- *Type*: statement
+
+validate_slength
+----------------
+Validate that the first argument is a string (or an array of strings), and
+less/equal to than the length of the second argument. It fails if the first
+argument is not a string or array of strings, and if arg 2 is not convertable
+to a number.
+
+The following values will pass:
+
+ validate_slength("discombobulate",17)
+ validate_slength(["discombobulate","moo"],17)
+
+The following valueis will not:
+
+ validate_slength("discombobulate",1)
+ validate_slength(["discombobulate","thermometer"],5)
+
+
+
+- *Type*: statement
+
+validate_string
+---------------
+Validate that all passed values are string data structures. Abort catalog
+compilation if any value fails this check.
+
+The following values will pass:
+
+ $my_string = "one two"
+ validate_string($my_string, 'three')
+
+The following values will fail, causing compilation to abort:
+
+ validate_string(true)
+ validate_string([ 'some', 'array' ])
+ $undefined = undef
+ validate_string($undefined)
+
+
+- *Type*: statement
+
+values
+------
+When given a hash this function will return the values of that hash.
+
+*Examples:*
+
+ $hash = {
+ 'a' => 1,
+ 'b' => 2,
+ 'c' => 3,
+ }
+ values($hash)
+
+This example would return:
+
+ [1,2,3]
+
+
+- *Type*: rvalue
+
+values_at
+---------
+Finds value inside an array based on location.
+
+The first argument is the array you want to analyze, and the second element can
+be a combination of:
+
+* A single numeric index
+* A range in the form of 'start-stop' (eg. 4-9)
+* An array combining the above
+
+*Examples*:
+
+ values_at(['a','b','c'], 2)
+
+Would return ['c'].
+
+ values_at(['a','b','c'], ["0-1"])
+
+Would return ['a','b'].
+
+ values_at(['a','b','c','d','e'], [0, "2-3"])
+
+Would return ['a','c','d'].
- * getvar
- * has\_key
- * loadyaml
- * merge.rb
- * validate\_array
- * validate\_bool
- * validate\_hash
- * validate\_re
- * validate\_string
-## validate\_hash ##
+- *Type*: rvalue
- $somehash = { 'one' => 'two' }
- validate\_hash($somehash)
+zip
+---
+Takes one element from first array and merges corresponding elements from second array. This generates a sequence of n-element arrays, where n is one more than the count of arguments.
-## getvar() ##
+*Example:*
-This function aims to look up variables in user-defined namespaces within
-puppet. Note, if the namespace is a class, it should already be evaluated
-before the function is used.
+ zip(['1','2','3'],['4','5','6'])
- $namespace = 'site::data'
- include "${namespace}"
- $myvar = getvar("${namespace}::myvar")
+Would result in:
-## Facts ##
+ ["1", "4"], ["2", "5"], ["3", "6"]
-Facts in `/etc/facter/facts.d` and `/etc/puppetlabs/facter/facts.d` are now loaded
-automatically. This is a direct copy of R.I. Pienaar's custom facter fact
-located at:
-[https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d](https://github.com/ripienaar/facter-facts/tree/master/facts-dot-d)
+- *Type*: rvalue
+*This page autogenerated on 2013-04-11 13:54:25 -0700*
diff --git a/README_DEVELOPER.markdown b/README_DEVELOPER.markdown
new file mode 100644
index 0000000..04349ed
--- /dev/null
+++ b/README_DEVELOPER.markdown
@@ -0,0 +1,35 @@
+Puppet Specific Facts
+=====================
+
+Facter is meant to stand alone and apart from Puppet. However, Facter often
+runs inside Puppet and all custom facts included in the stdlib module will
+almost always be evaluated in the context of Puppet and Facter working
+together.
+
+Still, we don't want to write custom facts that blow up in the users face if
+Puppet is not loaded in memory. This is often the case if the user runs
+`facter` without also supplying the `--puppet` flag.
+
+Ah! But Jeff, the custom fact won't be in the `$LOAD_PATH` unless the user
+supplies `--facter`! You might say...
+
+Not (always) true I say! If the user happens to have a CWD of
+`<modulepath>/stdlib/lib` then the facts will automatically be evaluated and
+blow up.
+
+In any event, it's pretty easy to write a fact that has no value if Puppet is
+not loaded. Simply do it like this:
+
+ Facter.add(:node_vardir) do
+ setcode do
+ # This will be nil if Puppet is not available.
+ Facter::Util::PuppetSettings.with_puppet do
+ Puppet[:vardir]
+ end
+ end
+ end
+
+The `Facter::Util::PuppetSettings.with_puppet` method accepts a block and
+yields to it only if the Puppet library is loaded. If the Puppet library is
+not loaded, then the method silently returns `nil` which Facter interprets as
+an undefined fact value. The net effect is that the fact won't be set.
diff --git a/README_SPECS.markdown b/README_SPECS.markdown
new file mode 100644
index 0000000..917b631
--- /dev/null
+++ b/README_SPECS.markdown
@@ -0,0 +1,7 @@
+NOTE
+====
+
+This project's specs depend on puppet core, and thus they require the
+`puppetlabs_spec_helper` project. For more information please see the README
+in that project, which can be found here: [puppetlabs spec
+helper](https://github.com/puppetlabs/puppetlabs_spec_helper)
diff --git a/RELEASE_PROCESS.markdown b/RELEASE_PROCESS.markdown
index ea40d5d..0f9328e 100644
--- a/RELEASE_PROCESS.markdown
+++ b/RELEASE_PROCESS.markdown
@@ -1,13 +1,24 @@
-# Releasing this module #
+# Contributing to this module #
* Work in a topic branch
* Submit a github pull request
* Address any comments / feeback
* Merge into master using --no-ff
+
+# Releasing this module #
+
+ * This module adheres to http://semver.org/
+ * Look for API breaking changes using git diff vX.Y.Z..master
+ * If no API breaking changes, the minor version may be bumped.
+ * If there are API breaking changes, the major version must be bumped.
+ * If there are only small minor changes, the patch version may be bumped.
* Update the CHANGELOG
* Update the Modulefile
- * Create an annotated tag with git tag -a X.Y.Z -m 'version X.Y.Z'
+ * Commit these changes with a message along the lines of "Update CHANGELOG and
+ Modulefile for release"
+ * Create an annotated tag with git tag -a vX.Y.Z -m 'version X.Y.Z' (NOTE the
+ leading v as per semver.org)
* Push the tag with git push origin --tags
- * Build a new package with puppet-module
+ * Build a new package with puppet-module or the rake build task if it exists
* Publish the new package to the forge
-
+ * Bonus points for an announcement to puppet-users.
diff --git a/Rakefile b/Rakefile
index 01b2a31..14f1c24 100644
--- a/Rakefile
+++ b/Rakefile
@@ -1,16 +1,2 @@
-require 'rake'
-require 'rspec/core/rake_task'
-
-task :default => [:test]
-
-desc 'Run RSpec'
-RSpec::Core::RakeTask.new(:test) do |t|
- t.pattern = 'spec/{unit}/**/*.rb'
- t.rspec_opts = ['--color']
-end
-
-desc 'Generate code coverage'
-RSpec::Core::RakeTask.new(:coverage) do |t|
- t.rcov = true
- t.rcov_opts = ['--exclude', 'spec']
-end
+require 'rubygems'
+require 'puppetlabs_spec_helper/rake_tasks'
diff --git a/lib/facter/facter_dot_d.rb b/lib/facter/facter_dot_d.rb
index 90586a9..e414b20 100644
--- a/lib/facter/facter_dot_d.rb
+++ b/lib/facter/facter_dot_d.rb
@@ -1,4 +1,5 @@
-# A Facter plugin that loads facts from /etc/facts.d.
+# A Facter plugin that loads facts from /etc/facter/facts.d
+# and /etc/puppetlabs/facter/facts.d.
#
# Facts can be in the form of JSON, YAML or Text files
# and any executable that returns key=value pairs.
@@ -10,174 +11,192 @@
# The cache is stored in /tmp/facts_cache.yaml as a mode
# 600 file and will have the end result of not calling your
# fact scripts more often than is needed
+
class Facter::Util::DotD
- require 'yaml'
+ require 'yaml'
- def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml")
- @dir = dir
- @cache_file = cache_file
- @cache = nil
- @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml}
- end
+ def initialize(dir="/etc/facts.d", cache_file="/tmp/facts_cache.yml")
+ @dir = dir
+ @cache_file = cache_file
+ @cache = nil
+ @types = {".txt" => :txt, ".json" => :json, ".yaml" => :yaml}
+ end
- def entries
- Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) }
- rescue
- []
- end
+ def entries
+ Dir.entries(@dir).reject{|f| f =~ /^\.|\.ttl$/}.sort.map {|f| File.join(@dir, f) }
+ rescue
+ []
+ end
- def fact_type(file)
- extension = File.extname(file)
+ def fact_type(file)
+ extension = File.extname(file)
- type = @types[extension] || :unknown
+ type = @types[extension] || :unknown
- type = :script if type == :unknown && File.executable?(file)
+ type = :script if type == :unknown && File.executable?(file)
- return type
- end
+ return type
+ end
- def txt_parser(file)
- File.readlines(file).each do |line|
- if line =~ /^(.+)=(.+)$/
- var = $1; val = $2
+ def txt_parser(file)
+ File.readlines(file).each do |line|
+ if line =~ /^(.+)=(.+)$/
+ var = $1; val = $2
- Facter.add(var) do
- setcode { val }
- end
- end
+ Facter.add(var) do
+ setcode { val }
end
- rescue Exception => e
- Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}")
+ end
end
-
- def json_parser(file)
- begin
- require 'json'
- rescue LoadError
- require 'rubygems'
- retry
- end
-
- JSON.load(File.read(file)).each_pair do |f, v|
- Facter.add(f) do
- setcode { v }
- end
- end
- rescue Exception => e
- Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}")
+ rescue Exception => e
+ Facter.warn("Failed to handle #{file} as text facts: #{e.class}: #{e}")
+ end
+
+ def json_parser(file)
+ begin
+ require 'json'
+ rescue LoadError
+ retry if require 'rubygems'
+ raise
end
- def yaml_parser(file)
- require 'yaml'
-
- YAML.load_file(file).each_pair do |f, v|
- Facter.add(f) do
- setcode { v }
- end
- end
- rescue Exception => e
- Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}")
+ JSON.load(File.read(file)).each_pair do |f, v|
+ Facter.add(f) do
+ setcode { v }
+ end
end
+ rescue Exception => e
+ Facter.warn("Failed to handle #{file} as json facts: #{e.class}: #{e}")
+ end
- def script_parser(file)
- result = cache_lookup(file)
- ttl = cache_time(file)
-
- unless result
- result = Facter::Util::Resolution.exec(file)
+ def yaml_parser(file)
+ require 'yaml'
- if ttl > 0
- Facter.debug("Updating cache for #{file}")
- cache_store(file, result)
- cache_save!
- end
- else
- Facter.debug("Using cached data for #{file}")
- end
+ YAML.load_file(file).each_pair do |f, v|
+ Facter.add(f) do
+ setcode { v }
+ end
+ end
+ rescue Exception => e
+ Facter.warn("Failed to handle #{file} as yaml facts: #{e.class}: #{e}")
+ end
+
+ def script_parser(file)
+ result = cache_lookup(file)
+ ttl = cache_time(file)
+
+ unless result
+ result = Facter::Util::Resolution.exec(file)
+
+ if ttl > 0
+ Facter.debug("Updating cache for #{file}")
+ cache_store(file, result)
+ cache_save!
+ end
+ else
+ Facter.debug("Using cached data for #{file}")
+ end
- result.split("\n").each do |line|
- if line =~ /^(.+)=(.+)$/
- var = $1; val = $2
+ result.split("\n").each do |line|
+ if line =~ /^(.+)=(.+)$/
+ var = $1; val = $2
- Facter.add(var) do
- setcode { val }
- end
- end
+ Facter.add(var) do
+ setcode { val }
end
- rescue Exception => e
- Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}")
- Facter.debug(e.backtrace.join("\n\t"))
+ end
end
+ rescue Exception => e
+ Facter.warn("Failed to handle #{file} as script facts: #{e.class}: #{e}")
+ Facter.debug(e.backtrace.join("\n\t"))
+ end
- def cache_save!
- cache = load_cache
- File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) }
- rescue
- end
+ def cache_save!
+ cache = load_cache
+ File.open(@cache_file, "w", 0600) {|f| f.write(YAML.dump(cache)) }
+ rescue
+ end
- def cache_store(file, data)
- load_cache
+ def cache_store(file, data)
+ load_cache
- @cache[file] = {:data => data, :stored => Time.now.to_i}
- rescue
- end
+ @cache[file] = {:data => data, :stored => Time.now.to_i}
+ rescue
+ end
- def cache_lookup(file)
- cache = load_cache
+ def cache_lookup(file)
+ cache = load_cache
- return nil if cache.empty?
+ return nil if cache.empty?
- ttl = cache_time(file)
+ ttl = cache_time(file)
- if cache[file]
- now = Time.now.to_i
+ if cache[file]
+ now = Time.now.to_i
- return cache[file][:data] if ttl == -1
- return cache[file][:data] if (now - cache[file][:stored]) <= ttl
- return nil
- else
- return nil
- end
- rescue
- return nil
+ return cache[file][:data] if ttl == -1
+ return cache[file][:data] if (now - cache[file][:stored]) <= ttl
+ return nil
+ else
+ return nil
+ end
+ rescue
+ return nil
+ end
+
+ def cache_time(file)
+ meta = file + ".ttl"
+
+ return File.read(meta).chomp.to_i
+ rescue
+ return 0
+ end
+
+ def load_cache
+ unless @cache
+ if File.exist?(@cache_file)
+ @cache = YAML.load_file(@cache_file)
+ else
+ @cache = {}
+ end
end
- def cache_time(file)
- meta = file + ".ttl"
+ return @cache
+ rescue
+ @cache = {}
+ return @cache
+ end
- return File.read(meta).chomp.to_i
- rescue
- return 0
- end
+ def create
+ entries.each do |fact|
+ type = fact_type(fact)
+ parser = "#{type}_parser"
- def load_cache
- unless @cache
- if File.exist?(@cache_file)
- @cache = YAML.load_file(@cache_file)
- else
- @cache = {}
- end
- end
+ if respond_to?("#{type}_parser")
+ Facter.debug("Parsing #{fact} using #{parser}")
- return @cache
- rescue
- @cache = {}
- return @cache
+ send(parser, fact)
+ end
end
+ end
+end
- def create
- entries.each do |fact|
- type = fact_type(fact)
- parser = "#{type}_parser"
-
- if respond_to?("#{type}_parser")
- Facter.debug("Parsing #{fact} using #{parser}")
- send(parser, fact)
- end
- end
+mdata = Facter.version.match(/(\d+)\.(\d+)\.(\d+)/)
+if mdata
+ (major, minor, patch) = mdata.captures.map { |v| v.to_i }
+ if major < 2
+ # Facter 1.7 introduced external facts support directly
+ unless major == 1 and minor > 6
+ Facter::Util::DotD.new("/etc/facter/facts.d").create
+ Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create
+
+ # Windows has a different configuration directory that defaults to a vendor
+ # specific sub directory of the %COMMON_APPDATA% directory.
+ if Dir.const_defined? 'COMMON_APPDATA' then
+ windows_facts_dot_d = File.join(Dir::COMMON_APPDATA, 'PuppetLabs', 'facter', 'facts.d')
+ Facter::Util::DotD.new(windows_facts_dot_d).create
+ end
end
+ end
end
-
-Facter::Util::DotD.new("/etc/facter/facts.d").create
-Facter::Util::DotD.new("/etc/puppetlabs/facter/facts.d").create
diff --git a/lib/facter/pe_version.rb b/lib/facter/pe_version.rb
new file mode 100644
index 0000000..0cc0f64
--- /dev/null
+++ b/lib/facter/pe_version.rb
@@ -0,0 +1,53 @@
+# Fact: is_pe, pe_version, pe_major_version, pe_minor_version, pe_patch_version
+#
+# Purpose: Return various facts about the PE state of the system
+#
+# Resolution: Uses a regex match against puppetversion to determine whether the
+# machine has Puppet Enterprise installed, and what version (overall, major,
+# minor, patch) is installed.
+#
+# Caveats:
+#
+Facter.add("pe_version") do
+ setcode do
+ pe_ver = Facter.value("puppetversion").match(/Puppet Enterprise (\d+\.\d+\.\d+)/)
+ pe_ver[1] if pe_ver
+ end
+end
+
+Facter.add("is_pe") do
+ setcode do
+ if Facter.value(:pe_version).to_s.empty? then
+ false
+ else
+ true
+ end
+ end
+end
+
+Facter.add("pe_major_version") do
+ confine :is_pe => true
+ setcode do
+ if pe_version = Facter.value(:pe_version)
+ pe_version.to_s.split('.')[0]
+ end
+ end
+end
+
+Facter.add("pe_minor_version") do
+ confine :is_pe => true
+ setcode do
+ if pe_version = Facter.value(:pe_version)
+ pe_version.to_s.split('.')[1]
+ end
+ end
+end
+
+Facter.add("pe_patch_version") do
+ confine :is_pe => true
+ setcode do
+ if pe_version = Facter.value(:pe_version)
+ pe_version.to_s.split('.')[2]
+ end
+ end
+end
diff --git a/lib/facter/puppet_vardir.rb b/lib/facter/puppet_vardir.rb
new file mode 100644
index 0000000..0e6af40
--- /dev/null
+++ b/lib/facter/puppet_vardir.rb
@@ -0,0 +1,26 @@
+# This facter fact returns the value of the Puppet vardir setting for the node
+# running puppet or puppet agent. The intent is to enable Puppet modules to
+# automatically have insight into a place where they can place variable data,
+# regardless of the node's platform.
+#
+# The value should be directly usable in a File resource path attribute.
+
+
+begin
+ require 'facter/util/puppet_settings'
+rescue LoadError => e
+ # puppet apply does not add module lib directories to the $LOAD_PATH (See
+ # #4248). It should (in the future) but for the time being we need to be
+ # defensive which is what this rescue block is doing.
+ rb_file = File.join(File.dirname(__FILE__), 'util', 'puppet_settings.rb')
+ load rb_file if File.exists?(rb_file) or raise e
+end
+
+Facter.add(:puppet_vardir) do
+ setcode do
+ # This will be nil if Puppet is not available.
+ Facter::Util::PuppetSettings.with_puppet do
+ Puppet[:vardir]
+ end
+ end
+end
diff --git a/lib/facter/root_home.rb b/lib/facter/root_home.rb
index 61fcf39..8249f7d 100644
--- a/lib/facter/root_home.rb
+++ b/lib/facter/root_home.rb
@@ -7,7 +7,9 @@ module Facter::Util::RootHome
def get_root_home
root_ent = Facter::Util::Resolution.exec("getent passwd root")
# The home directory is the sixth element in the passwd entry
- root_ent.split(":")[5]
+ # If the platform doesn't have getent, root_ent will be nil and we should
+ # return it straight away.
+ root_ent && root_ent.split(":")[5]
end
end
end
diff --git a/lib/facter/util/puppet_settings.rb b/lib/facter/util/puppet_settings.rb
new file mode 100644
index 0000000..1ad9452
--- /dev/null
+++ b/lib/facter/util/puppet_settings.rb
@@ -0,0 +1,21 @@
+module Facter
+ module Util
+ module PuppetSettings
+ # This method is intended to provide a convenient way to evaluate a
+ # Facter code block only if Puppet is loaded. This is to account for the
+ # situation where the fact happens to be in the load path, but Puppet is
+ # not loaded for whatever reason. Perhaps the user is simply running
+ # facter without the --puppet flag and they happen to be working in a lib
+ # directory of a module.
+ def self.with_puppet
+ begin
+ Module.const_get("Puppet")
+ rescue NameError
+ nil
+ else
+ yield
+ end
+ end
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/abs.rb b/lib/puppet/parser/functions/abs.rb
index ade5462..11d2d7f 100644
--- a/lib/puppet/parser/functions/abs.rb
+++ b/lib/puppet/parser/functions/abs.rb
@@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:abs, :type => :rvalue, :doc => <<-EOS
- Returns the absolute value of a number, for example -34.56 becomes
+ Returns the absolute value of a number, for example -34.56 becomes
34.56. Takes a single integer and float value as an argument.
EOS
) do |arguments|
diff --git a/lib/puppet/parser/functions/any2array.rb b/lib/puppet/parser/functions/any2array.rb
new file mode 100644
index 0000000..e71407e
--- /dev/null
+++ b/lib/puppet/parser/functions/any2array.rb
@@ -0,0 +1,33 @@
+#
+# any2array.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:any2array, :type => :rvalue, :doc => <<-EOS
+This converts any object to an array containing that object. Empty argument
+lists are converted to an empty array. Arrays are left untouched. Hashes are
+converted to arrays of alternating keys and values.
+ EOS
+ ) do |arguments|
+
+ if arguments.empty?
+ return []
+ end
+
+ if arguments.length == 1
+ if arguments[0].kind_of?(Array)
+ return arguments[0]
+ elsif arguments[0].kind_of?(Hash)
+ result = []
+ arguments[0].each do |key, value|
+ result << key << value
+ end
+ return result
+ end
+ end
+
+ return arguments
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/base64.rb b/lib/puppet/parser/functions/base64.rb
new file mode 100644
index 0000000..d9a590a
--- /dev/null
+++ b/lib/puppet/parser/functions/base64.rb
@@ -0,0 +1,37 @@
+module Puppet::Parser::Functions
+
+ newfunction(:base64, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
+
+ Base64 encode or decode a string based on the command and the string submitted
+
+ Usage:
+
+ $encodestring = base64('encode','thestring')
+ $decodestring = base64('decode','dGhlc3RyaW5n')
+
+ ENDHEREDOC
+
+ require 'base64'
+
+ raise Puppet::ParseError, ("base64(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2
+
+ actions = ['encode','decode']
+
+ unless actions.include?(args[0])
+ raise Puppet::ParseError, ("base64(): the first argument must be one of 'encode' or 'decode'")
+ end
+
+ unless args[1].is_a?(String)
+ raise Puppet::ParseError, ("base64(): the second argument must be a string to base64")
+ end
+
+ case args[0]
+ when 'encode'
+ result = Base64.encode64(args[1])
+ when 'decode'
+ result = Base64.decode64(args[1])
+ end
+
+ return result
+ end
+end
diff --git a/lib/puppet/parser/functions/chomp.rb b/lib/puppet/parser/functions/chomp.rb
index c99d139..4564a00 100644
--- a/lib/puppet/parser/functions/chomp.rb
+++ b/lib/puppet/parser/functions/chomp.rb
@@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:chomp, :type => :rvalue, :doc => <<-'EOS'
- Removes the record separator from the end of a string or an array of
+ Removes the record separator from the end of a string or an array of
strings, for example `hello\n` becomes `hello`.
Requires a single string or array as an input.
EOS
diff --git a/lib/puppet/parser/functions/chop.rb b/lib/puppet/parser/functions/chop.rb
index 636b990..f242af3 100644
--- a/lib/puppet/parser/functions/chop.rb
+++ b/lib/puppet/parser/functions/chop.rb
@@ -4,9 +4,9 @@
module Puppet::Parser::Functions
newfunction(:chop, :type => :rvalue, :doc => <<-'EOS'
- Returns a new string with the last character removed. If the string ends
- with `\r\n`, both characters are removed. Applying chop to an empty
- string returns an empty string. If you wish to merely remove record
+ Returns a new string with the last character removed. If the string ends
+ with `\r\n`, both characters are removed. Applying chop to an empty
+ string returns an empty string. If you wish to merely remove record
separators then you should use the `chomp` function.
Requires a string or array of strings as input.
EOS
diff --git a/lib/puppet/parser/functions/concat.rb b/lib/puppet/parser/functions/concat.rb
new file mode 100644
index 0000000..c86aa00
--- /dev/null
+++ b/lib/puppet/parser/functions/concat.rb
@@ -0,0 +1,37 @@
+#
+# concat.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:concat, :type => :rvalue, :doc => <<-EOS
+Appends the contents of array 2 onto array 1.
+
+*Example:*
+
+ concat(['1','2','3'],['4','5','6'])
+
+Would result in:
+
+ ['1','2','3','4','5','6']
+ EOS
+ ) do |arguments|
+
+ # Check that 2 arguments have been given ...
+ raise(Puppet::ParseError, "concat(): Wrong number of arguments " +
+ "given (#{arguments.size} for 2)") if arguments.size != 2
+
+ a = arguments[0]
+ b = arguments[1]
+
+ # Check that both args are arrays.
+ unless a.is_a?(Array) and b.is_a?(Array)
+ raise(Puppet::ParseError, 'concat(): Requires array to work with')
+ end
+
+ result = a.concat(b)
+
+ return result
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/count.rb b/lib/puppet/parser/functions/count.rb
new file mode 100644
index 0000000..52de1b8
--- /dev/null
+++ b/lib/puppet/parser/functions/count.rb
@@ -0,0 +1,22 @@
+module Puppet::Parser::Functions
+ newfunction(:count, :type => :rvalue, :arity => -2, :doc => <<-EOS
+Takes an array as first argument and an optional second argument.
+Count the number of elements in array that matches second argument.
+If called with only an array it counts the number of elements that are not nil/undef.
+ EOS
+ ) do |args|
+
+ if (args.size > 2) then
+ raise(ArgumentError, "count(): Wrong number of arguments "+
+ "given #{args.size} for 1 or 2.")
+ end
+
+ collection, item = args
+
+ if item then
+ collection.count item
+ else
+ collection.count { |obj| obj != nil && obj != :undef && obj != '' }
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/defined_with_params.rb b/lib/puppet/parser/functions/defined_with_params.rb
new file mode 100644
index 0000000..d7df306
--- /dev/null
+++ b/lib/puppet/parser/functions/defined_with_params.rb
@@ -0,0 +1,35 @@
+# Test whether a given class or definition is defined
+require 'puppet/parser/functions'
+
+Puppet::Parser::Functions.newfunction(:defined_with_params,
+ :type => :rvalue,
+ :doc => <<-'ENDOFDOC'
+Takes a resource reference and an optional hash of attributes.
+
+Returns true if a resource with the specified attributes has already been added
+to the catalog, and false otherwise.
+
+ user { 'dan':
+ ensure => present,
+ }
+
+ if ! defined_with_params(User[dan], {'ensure' => 'present' }) {
+ user { 'dan': ensure => present, }
+ }
+ENDOFDOC
+) do |vals|
+ reference, params = vals
+ raise(ArgumentError, 'Must specify a reference') unless reference
+ if (! params) || params == ''
+ params = {}
+ end
+ ret = false
+ if resource = findresource(reference.to_s)
+ matches = params.collect do |key, value|
+ resource[key] == value
+ end
+ ret = params.empty? || !matches.include?(false)
+ end
+ Puppet.debug("Resource #{reference} was not determined to be defined")
+ ret
+end
diff --git a/lib/puppet/parser/functions/delete.rb b/lib/puppet/parser/functions/delete.rb
index ab8f75b..f814344 100644
--- a/lib/puppet/parser/functions/delete.rb
+++ b/lib/puppet/parser/functions/delete.rb
@@ -3,31 +3,43 @@
#
# TODO(Krzysztof Wilczynski): We need to add support for regular expression ...
-# TODO(Krzysztof Wilczynski): Support for strings and hashes too ...
module Puppet::Parser::Functions
newfunction(:delete, :type => :rvalue, :doc => <<-EOS
-Deletes a selected element from an array.
+Deletes all instances of a given element from an array, substring from a
+string, or key from a hash.
*Examples:*
- delete(['a','b','c'], 'b')
+ delete(['a','b','c','b'], 'b')
+ Would return: ['a','c']
-Would return: ['a','c']
+ delete({'a'=>1,'b'=>2,'c'=>3}, 'b')
+ Would return: {'a'=>1,'c'=>3}
+
+ delete('abracadabra', 'bra')
+ Would return: 'acada'
EOS
) do |arguments|
if (arguments.size != 2) then
raise(Puppet::ParseError, "delete(): Wrong number of arguments "+
- "given #{arguments.size} for 2")
+ "given #{arguments.size} for 2.")
end
- a = arguments[0]
+ collection = arguments[0]
item = arguments[1]
- a.delete(item)
- a
-
+ case collection
+ when Array, Hash
+ collection.delete item
+ when String
+ collection.gsub! item, ''
+ else
+ raise(TypeError, "delete(): First argument must be an Array, " +
+ "String, or Hash. Given an argument of class #{collection.class}.")
+ end
+ collection
end
end
diff --git a/lib/puppet/parser/functions/difference.rb b/lib/puppet/parser/functions/difference.rb
new file mode 100644
index 0000000..cd258f7
--- /dev/null
+++ b/lib/puppet/parser/functions/difference.rb
@@ -0,0 +1,36 @@
+#
+# difference.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:difference, :type => :rvalue, :doc => <<-EOS
+This function returns the difference between two arrays.
+The returned array is a copy of the original array, removing any items that
+also appear in the second array.
+
+*Examples:*
+
+ difference(["a","b","c"],["b","c","d"])
+
+Would return: ["a"]
+ EOS
+ ) do |arguments|
+
+ # Two arguments are required
+ raise(Puppet::ParseError, "difference(): Wrong number of arguments " +
+ "given (#{arguments.size} for 2)") if arguments.size != 2
+
+ first = arguments[0]
+ second = arguments[1]
+
+ unless first.is_a?(Array) && second.is_a?(Array)
+ raise(Puppet::ParseError, 'difference(): Requires 2 arrays')
+ end
+
+ result = first - second
+
+ return result
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/dirname.rb b/lib/puppet/parser/functions/dirname.rb
new file mode 100644
index 0000000..ea8cc1e
--- /dev/null
+++ b/lib/puppet/parser/functions/dirname.rb
@@ -0,0 +1,15 @@
+module Puppet::Parser::Functions
+ newfunction(:dirname, :type => :rvalue, :doc => <<-EOS
+ Returns the dirname of a path.
+ EOS
+ ) do |arguments|
+
+ raise(Puppet::ParseError, "dirname(): Wrong number of arguments " +
+ "given (#{arguments.size} for 1)") if arguments.size < 1
+
+ path = arguments[0]
+ return File.dirname(path)
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/ensure_packages.rb b/lib/puppet/parser/functions/ensure_packages.rb
new file mode 100644
index 0000000..450ea02
--- /dev/null
+++ b/lib/puppet/parser/functions/ensure_packages.rb
@@ -0,0 +1,24 @@
+#
+# ensure_packages.rb
+#
+require 'puppet/parser/functions'
+
+module Puppet::Parser::Functions
+ newfunction(:ensure_packages, :type => :statement, :doc => <<-EOS
+Takes a list of packages and only installs them if they don't already exist.
+ EOS
+ ) do |arguments|
+
+ raise(Puppet::ParseError, "ensure_packages(): Wrong number of arguments " +
+ "given (#{arguments.size} for 1)") if arguments.size != 1
+ raise(Puppet::ParseError, "ensure_packages(): Requires array " +
+ "given (#{arguments[0].class})") if !arguments[0].kind_of?(Array)
+
+ Puppet::Parser::Functions.function(:ensure_resource)
+ arguments[0].each { |package_name|
+ function_ensure_resource(['package', package_name, {'ensure' => 'present' } ])
+ }
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/ensure_resource.rb b/lib/puppet/parser/functions/ensure_resource.rb
new file mode 100644
index 0000000..a9a1733
--- /dev/null
+++ b/lib/puppet/parser/functions/ensure_resource.rb
@@ -0,0 +1,45 @@
+# Test whether a given class or definition is defined
+require 'puppet/parser/functions'
+
+Puppet::Parser::Functions.newfunction(:ensure_resource,
+ :type => :statement,
+ :doc => <<-'ENDOFDOC'
+Takes a resource type, title, and a list of attributes that describe a
+resource.
+
+ user { 'dan':
+ ensure => present,
+ }
+
+This example only creates the resource if it does not already exist:
+
+ ensure_resource('user, 'dan', {'ensure' => 'present' })
+
+If the resource already exists but does not match the specified parameters,
+this function will attempt to recreate the resource leading to a duplicate
+resource definition error.
+
+An array of resources can also be passed in and each will be created with
+the type and parameters specified if it doesn't already exist.
+
+ ensure_resource('user', ['dan','alex'], {'ensure' => 'present'})
+
+ENDOFDOC
+) do |vals|
+ type, title, params = vals
+ raise(ArgumentError, 'Must specify a type') unless type
+ raise(ArgumentError, 'Must specify a title') unless title
+ params ||= {}
+
+ items = [title].flatten
+
+ items.each do |item|
+ Puppet::Parser::Functions.function(:defined_with_params)
+ if function_defined_with_params(["#{type}[#{item}]", params])
+ Puppet.debug("Resource #{type}[#{item}] not created because it already exists")
+ else
+ Puppet::Parser::Functions.function(:create_resources)
+ function_create_resources([type.capitalize, { item => params }])
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/flatten.rb b/lib/puppet/parser/functions/flatten.rb
index 781da78..a1ed183 100644
--- a/lib/puppet/parser/functions/flatten.rb
+++ b/lib/puppet/parser/functions/flatten.rb
@@ -16,7 +16,7 @@ Would return: ['a','b','c']
) do |arguments|
raise(Puppet::ParseError, "flatten(): Wrong number of arguments " +
- "given (#{arguments.size} for 1)") if arguments.size < 1
+ "given (#{arguments.size} for 1)") if arguments.size != 1
array = arguments[0]
diff --git a/lib/puppet/parser/functions/floor.rb b/lib/puppet/parser/functions/floor.rb
new file mode 100644
index 0000000..a401923
--- /dev/null
+++ b/lib/puppet/parser/functions/floor.rb
@@ -0,0 +1,20 @@
+module Puppet::Parser::Functions
+ newfunction(:floor, :type => :rvalue, :doc => <<-EOS
+ Returns the largest integer less or equal to the argument.
+ Takes a single numeric value as an argument.
+ EOS
+ ) do |arguments|
+
+ raise(Puppet::ParseError, "floor(): Wrong number of arguments " +
+ "given (#{arguments.size} for 1)") if arguments.size != 1
+
+ arg = arguments[0]
+
+ raise(Puppet::ParseError, "floor(): Wrong argument type " +
+ "given (#{arg.class} for Numeric)") if arg.is_a?(Numeric) == false
+
+ arg.floor
+ end
+end
+
+# vim: set ts=2 sw=2 et :
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/lib/puppet/parser/functions/get_module_path.rb b/lib/puppet/parser/functions/get_module_path.rb
new file mode 100644
index 0000000..1421b91
--- /dev/null
+++ b/lib/puppet/parser/functions/get_module_path.rb
@@ -0,0 +1,17 @@
+module Puppet::Parser::Functions
+ newfunction(:get_module_path, :type =>:rvalue, :doc => <<-EOT
+ Returns the absolute path of the specified module for the current
+ environment.
+
+ Example:
+ $module_path = get_module_path('stdlib')
+ EOT
+ ) do |args|
+ raise(Puppet::ParseError, "get_module_path(): Wrong number of arguments, expects one") unless args.size == 1
+ if module_path = Puppet::Module.find(args[0], compiler.environment.to_s)
+ module_path.path
+ else
+ raise(Puppet::ParseError, "Could not find module #{args[0]} in environment #{compiler.environment}")
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/getparam.rb b/lib/puppet/parser/functions/getparam.rb
new file mode 100644
index 0000000..6d51006
--- /dev/null
+++ b/lib/puppet/parser/functions/getparam.rb
@@ -0,0 +1,35 @@
+# Test whether a given class or definition is defined
+require 'puppet/parser/functions'
+
+Puppet::Parser::Functions.newfunction(:getparam,
+ :type => :rvalue,
+ :doc => <<-'ENDOFDOC'
+Takes a resource reference and name of the parameter and
+returns value of resource's parameter.
+
+*Examples:*
+
+ define example_resource($param) {
+ }
+
+ example_resource { "example_resource_instance":
+ param => "param_value"
+ }
+
+ getparam(Example_resource["example_resource_instance"], "param")
+
+Would return: param_value
+ENDOFDOC
+) do |vals|
+ reference, param = vals
+ raise(ArgumentError, 'Must specify a reference') unless reference
+ raise(ArgumentError, 'Must specify name of a parameter') unless param and param.instance_of? String
+
+ return '' if param.empty?
+
+ if resource = findresource(reference.to_s)
+ return resource[param] if resource[param]
+ end
+
+ return ''
+end
diff --git a/lib/puppet/parser/functions/getvar.rb b/lib/puppet/parser/functions/getvar.rb
index ffd774d..1621149 100644
--- a/lib/puppet/parser/functions/getvar.rb
+++ b/lib/puppet/parser/functions/getvar.rb
@@ -5,11 +5,14 @@ module Puppet::Parser::Functions
For example:
- $foo = getvar('site::data::foo')
+ $foo = getvar('site::data::foo')
+ # Equivalent to $foo = $site::data::foo
This is useful if the namespace itself is stored in a string:
- $bar = getvar("${datalocation}::bar")
+ $datalocation = 'site::data'
+ $bar = getvar("${datalocation}::bar")
+ # Equivalent to $bar = $site::data::bar
ENDHEREDOC
unless args.length == 1
diff --git a/lib/puppet/parser/functions/has_interface_with.rb b/lib/puppet/parser/functions/has_interface_with.rb
new file mode 100644
index 0000000..7f150a7
--- /dev/null
+++ b/lib/puppet/parser/functions/has_interface_with.rb
@@ -0,0 +1,52 @@
+#
+# has_interface_with
+#
+
+module Puppet::Parser::Functions
+ newfunction(:has_interface_with, :type => :rvalue, :doc => <<-EOS
+Returns boolean based on kind and value:
+ * macaddress
+ * netmask
+ * ipaddress
+ * network
+
+has_interface_with("macaddress", "x:x:x:x:x:x")
+has_interface_with("ipaddress", "127.0.0.1") => true
+etc.
+
+If no "kind" is given, then the presence of the interface is checked:
+has_interface_with("lo") => true
+ EOS
+ ) do |args|
+
+ raise(Puppet::ParseError, "has_interface_with(): Wrong number of arguments " +
+ "given (#{args.size} for 1 or 2)") if args.size < 1 or args.size > 2
+
+ interfaces = lookupvar('interfaces')
+
+ # If we do not have any interfaces, then there are no requested attributes
+ return false if (interfaces == :undefined)
+
+ interfaces = interfaces.split(',')
+
+ if args.size == 1
+ return interfaces.member?(args[0])
+ end
+
+ kind, value = args
+
+ if lookupvar(kind) == value
+ return true
+ end
+
+ result = false
+ interfaces.each do |iface|
+ if value == lookupvar("#{kind}_#{iface}")
+ result = true
+ break
+ end
+ end
+
+ result
+ end
+end
diff --git a/lib/puppet/parser/functions/has_ip_address.rb b/lib/puppet/parser/functions/has_ip_address.rb
new file mode 100644
index 0000000..842c8ec
--- /dev/null
+++ b/lib/puppet/parser/functions/has_ip_address.rb
@@ -0,0 +1,25 @@
+#
+# has_ip_address
+#
+
+module Puppet::Parser::Functions
+ newfunction(:has_ip_address, :type => :rvalue, :doc => <<-EOS
+Returns true if the client has the requested IP address on some interface.
+
+This function iterates through the 'interfaces' fact and checks the
+'ipaddress_IFACE' facts, performing a simple string comparison.
+ EOS
+ ) do |args|
+
+ raise(Puppet::ParseError, "has_ip_address(): Wrong number of arguments " +
+ "given (#{args.size} for 1)") if args.size != 1
+
+ Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
+ unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)
+
+ function_has_interface_with(['ipaddress', args[0]])
+
+ end
+end
+
+# vim:sts=2 sw=2
diff --git a/lib/puppet/parser/functions/has_ip_network.rb b/lib/puppet/parser/functions/has_ip_network.rb
new file mode 100644
index 0000000..9ccf902
--- /dev/null
+++ b/lib/puppet/parser/functions/has_ip_network.rb
@@ -0,0 +1,25 @@
+#
+# has_ip_network
+#
+
+module Puppet::Parser::Functions
+ newfunction(:has_ip_network, :type => :rvalue, :doc => <<-EOS
+Returns true if the client has an IP address within the requested network.
+
+This function iterates through the 'interfaces' fact and checks the
+'network_IFACE' facts, performing a simple string comparision.
+ EOS
+ ) do |args|
+
+ raise(Puppet::ParseError, "has_ip_network(): Wrong number of arguments " +
+ "given (#{args.size} for 1)") if args.size != 1
+
+ Puppet::Parser::Functions.autoloader.load(:has_interface_with) \
+ unless Puppet::Parser::Functions.autoloader.loaded?(:has_interface_with)
+
+ function_has_interface_with(['network', args[0]])
+
+ end
+end
+
+# vim:sts=2 sw=2
diff --git a/lib/puppet/parser/functions/has_key.rb b/lib/puppet/parser/functions/has_key.rb
index 9c1c4c3..4657cc2 100644
--- a/lib/puppet/parser/functions/has_key.rb
+++ b/lib/puppet/parser/functions/has_key.rb
@@ -1,16 +1,17 @@
module Puppet::Parser::Functions
newfunction(:has_key, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
- determine if a hash has a certain key value.
+ Determine if a hash has a certain key value.
Example:
- $my_hash = {'key_one' => 'value_one'}
- if has_key($my_hash, 'key_two') {
- notice('we will not reach here')
- }
- if has_key($my_hash, 'key_one') {
- notice('this will be printed')
- }
+
+ $my_hash = {'key_one' => 'value_one'}
+ if has_key($my_hash, 'key_two') {
+ notice('we will not reach here')
+ }
+ if has_key($my_hash, 'key_one') {
+ notice('this will be printed')
+ }
ENDHEREDOC
diff --git a/lib/puppet/parser/functions/hash.rb b/lib/puppet/parser/functions/hash.rb
index 453ba1e..8cc4823 100644
--- a/lib/puppet/parser/functions/hash.rb
+++ b/lib/puppet/parser/functions/hash.rb
@@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:hash, :type => :rvalue, :doc => <<-EOS
-This function converts and array into a hash.
+This function converts an array into a hash.
*Examples:*
diff --git a/lib/puppet/parser/functions/intersection.rb b/lib/puppet/parser/functions/intersection.rb
new file mode 100644
index 0000000..48f02e9
--- /dev/null
+++ b/lib/puppet/parser/functions/intersection.rb
@@ -0,0 +1,34 @@
+#
+# intersection.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:intersection, :type => :rvalue, :doc => <<-EOS
+This function returns an array an intersection of two.
+
+*Examples:*
+
+ intersection(["a","b","c"],["b","c","d"])
+
+Would return: ["b","c"]
+ EOS
+ ) do |arguments|
+
+ # Two arguments are required
+ raise(Puppet::ParseError, "intersection(): Wrong number of arguments " +
+ "given (#{arguments.size} for 2)") if arguments.size != 2
+
+ first = arguments[0]
+ second = arguments[1]
+
+ unless first.is_a?(Array) && second.is_a?(Array)
+ raise(Puppet::ParseError, 'intersection(): Requires 2 arrays')
+ end
+
+ result = first & second
+
+ return result
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/is_domain_name.rb b/lib/puppet/parser/functions/is_domain_name.rb
index 4e92939..5826dc0 100644
--- a/lib/puppet/parser/functions/is_domain_name.rb
+++ b/lib/puppet/parser/functions/is_domain_name.rb
@@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:is_domain_name, :type => :rvalue, :doc => <<-EOS
-Returns true if the string passed to this function is a valid IP address. Support for IPv4 and IPv6 address types is included.
+Returns true if the string passed to this function is a syntactically correct domain name.
EOS
) do |arguments|
@@ -15,11 +15,31 @@ Returns true if the string passed to this function is a valid IP address. Suppor
domain = arguments[0]
- if domain =~ /^(([a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])\.?$/ then
- return true
- else
- return false
+ # Limits (rfc1035, 3.1)
+ domain_max_length=255
+ label_min_length=1
+ label_max_length=63
+
+ # Allow ".", it is the top level domain
+ return true if domain == '.'
+
+ # Remove the final dot, if present.
+ domain.chomp!('.')
+
+ # Check the whole domain
+ return false if domain.empty?
+ return false if domain.length > domain_max_length
+
+ # Check each label in the domain
+ labels = domain.split('.')
+ vlabels = labels.each do |label|
+ break if label.length < label_min_length
+ break if label.length > label_max_length
+ break if label[-1..-1] == '-'
+ break if label[0..0] == '-'
+ break unless /^[a-z\d-]+$/i.match(label)
end
+ return vlabels == labels
end
end
diff --git a/lib/puppet/parser/functions/is_float.rb b/lib/puppet/parser/functions/is_float.rb
index 2fc05ba..911f3c2 100644
--- a/lib/puppet/parser/functions/is_float.rb
+++ b/lib/puppet/parser/functions/is_float.rb
@@ -15,7 +15,7 @@ Returns true if the variable passed to this function is a float.
value = arguments[0]
- if value != value.to_f.to_s then
+ if value != value.to_f.to_s and !value.is_a? Float then
return false
else
return true
diff --git a/lib/puppet/parser/functions/is_function_available.rb b/lib/puppet/parser/functions/is_function_available.rb
new file mode 100644
index 0000000..6cbd35c
--- /dev/null
+++ b/lib/puppet/parser/functions/is_function_available.rb
@@ -0,0 +1,23 @@
+#
+# is_function_available.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:is_function_available, :type => :rvalue, :doc => <<-EOS
+This function accepts a string as an argument, determines whether the
+Puppet runtime has access to a function by that name. It returns a
+true if the function exists, false if not.
+ EOS
+ ) do |arguments|
+
+ if (arguments.size != 1) then
+ raise(Puppet::ParseError, "is_function_available?(): Wrong number of arguments "+
+ "given #{arguments.size} for 1")
+ end
+
+ function = Puppet::Parser::Functions.function(arguments[0].to_sym)
+ function.is_a?(String) and not function.empty?
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/is_integer.rb b/lib/puppet/parser/functions/is_integer.rb
index 8ee34f6..6b29e98 100644
--- a/lib/puppet/parser/functions/is_integer.rb
+++ b/lib/puppet/parser/functions/is_integer.rb
@@ -15,7 +15,7 @@ Returns true if the variable returned to this string is an integer.
value = arguments[0]
- if value != value.to_i.to_s then
+ if value != value.to_i.to_s and !value.is_a? Fixnum then
return false
else
return true
diff --git a/lib/puppet/parser/functions/is_ip_address.rb b/lib/puppet/parser/functions/is_ip_address.rb
index b4a9a15..a90adab 100644
--- a/lib/puppet/parser/functions/is_ip_address.rb
+++ b/lib/puppet/parser/functions/is_ip_address.rb
@@ -15,7 +15,7 @@ Returns true if the string passed to this function is a valid IP address.
"given #{arguments.size} for 1")
end
- begin
+ begin
ip = IPAddr.new(arguments[0])
rescue ArgumentError
return false
diff --git a/lib/puppet/parser/functions/is_numeric.rb b/lib/puppet/parser/functions/is_numeric.rb
index ce13ece..abf0321 100644
--- a/lib/puppet/parser/functions/is_numeric.rb
+++ b/lib/puppet/parser/functions/is_numeric.rb
@@ -15,7 +15,7 @@ Returns true if the variable passed to this function is a number.
value = arguments[0]
- if value == value.to_f.to_s or value == value.to_i.to_s then
+ if value == value.to_f.to_s or value == value.to_i.to_s or value.is_a? Numeric then
return true
else
return false
diff --git a/lib/puppet/parser/functions/join_keys_to_values.rb b/lib/puppet/parser/functions/join_keys_to_values.rb
new file mode 100644
index 0000000..e9924fe
--- /dev/null
+++ b/lib/puppet/parser/functions/join_keys_to_values.rb
@@ -0,0 +1,47 @@
+#
+# join.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:join_keys_to_values, :type => :rvalue, :doc => <<-EOS
+This function joins each key of a hash to that key's corresponding value with a
+separator. Keys and values are cast to strings. The return value is an array in
+which each element is one joined key/value pair.
+
+*Examples:*
+
+ join_keys_to_values({'a'=>1,'b'=>2}, " is ")
+
+Would result in: ["a is 1","b is 2"]
+ EOS
+ ) do |arguments|
+
+ # Validate the number of arguments.
+ if arguments.size != 2
+ raise(Puppet::ParseError, "join_keys_to_values(): Takes exactly two " +
+ "arguments, but #{arguments.size} given.")
+ end
+
+ # Validate the first argument.
+ hash = arguments[0]
+ if not hash.is_a?(Hash)
+ raise(TypeError, "join_keys_to_values(): The first argument must be a " +
+ "hash, but a #{hash.class} was given.")
+ end
+
+ # Validate the second argument.
+ separator = arguments[1]
+ if not separator.is_a?(String)
+ raise(TypeError, "join_keys_to_values(): The second argument must be a " +
+ "string, but a #{separator.class} was given.")
+ end
+
+ # Join the keys to their values.
+ hash.map do |k,v|
+ String(k) + separator + String(v)
+ end
+
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/loadyaml.rb b/lib/puppet/parser/functions/loadyaml.rb
index 0f16f69..10c4005 100644
--- a/lib/puppet/parser/functions/loadyaml.rb
+++ b/lib/puppet/parser/functions/loadyaml.rb
@@ -1,12 +1,12 @@
module Puppet::Parser::Functions
newfunction(:loadyaml, :type => :rvalue, :doc => <<-'ENDHEREDOC') do |args|
- Load a YAML file and return the data if it contains an Array, String, or Hash
- as a Puppet variable.
+ Load a YAML file containing an array, string, or hash, and return the data
+ in the corresponding native data type.
For example:
- $myhash = loadyaml('/etc/puppet/data/myhash.yaml')
+ $myhash = loadyaml('/etc/puppet/data/myhash.yaml')
ENDHEREDOC
unless args.length == 1
diff --git a/lib/puppet/parser/functions/max.rb b/lib/puppet/parser/functions/max.rb
new file mode 100644
index 0000000..60fb94a
--- /dev/null
+++ b/lib/puppet/parser/functions/max.rb
@@ -0,0 +1,21 @@
+module Puppet::Parser::Functions
+ newfunction(:max, :type => :rvalue, :doc => <<-EOS
+ Returns the highest value of all arguments.
+ Requires at least one argument.
+ EOS
+ ) do |args|
+
+ raise(Puppet::ParseError, "max(): Wrong number of arguments " +
+ "need at least one") if args.size == 0
+
+ # Sometimes we get numbers as numerics and sometimes as strings.
+ # We try to compare them as numbers when possible
+ return args.max do |a,b|
+ if a.to_s =~ /\A-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
+ a.to_f <=> b.to_f
+ else
+ a.to_s <=> b.to_s
+ end
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/merge.rb b/lib/puppet/parser/functions/merge.rb
index d2dc0f9..1b39f20 100644
--- a/lib/puppet/parser/functions/merge.rb
+++ b/lib/puppet/parser/functions/merge.rb
@@ -4,10 +4,13 @@ module Puppet::Parser::Functions
For example:
- $hash1 = {'one' => 1, 'two', => 2}
- $hash1 = {'two' => 2, 'three', => 2}
- $merged_hash = merge($hash1, $hash2)
- # merged_hash = {'one' => 1, 'two' => 2, 'three' => 2}
+ $hash1 = {'one' => 1, 'two', => 2}
+ $hash2 = {'two' => 'dos', 'three', => 'tres'}
+ $merged_hash = merge($hash1, $hash2)
+ # The resulting hash is equivalent to:
+ # $merged_hash = {'one' => 1, 'two' => 'dos', 'three' => 'tres'}
+
+ When there is a duplicate key, the key in the rightmost hash will "win."
ENDHEREDOC
@@ -19,6 +22,7 @@ module Puppet::Parser::Functions
accumulator = Hash.new
# Merge into the accumulator hash
args.each do |arg|
+ next if arg.is_a? String and arg.empty? # empty string is synonym for puppet's undef
unless arg.is_a?(Hash)
raise Puppet::ParseError, "merge: unexpected argument type #{arg.class}, only expects hash arguments"
end
diff --git a/lib/puppet/parser/functions/min.rb b/lib/puppet/parser/functions/min.rb
new file mode 100644
index 0000000..6bd6ebf
--- /dev/null
+++ b/lib/puppet/parser/functions/min.rb
@@ -0,0 +1,21 @@
+module Puppet::Parser::Functions
+ newfunction(:min, :type => :rvalue, :doc => <<-EOS
+ Returns the lowest value of all arguments.
+ Requires at least one argument.
+ EOS
+ ) do |args|
+
+ raise(Puppet::ParseError, "min(): Wrong number of arguments " +
+ "need at least one") if args.size == 0
+
+ # Sometimes we get numbers as numerics and sometimes as strings.
+ # We try to compare them as numbers when possible
+ return args.min do |a,b|
+ if a.to_s =~ /\A^-?\d+(.\d+)?\z/ and b.to_s =~ /\A-?\d+(.\d+)?\z/ then
+ a.to_f <=> b.to_f
+ else
+ a.to_s <=> b.to_s
+ end
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/num2bool.rb b/lib/puppet/parser/functions/num2bool.rb
index 874db22..af0e6ed 100644
--- a/lib/puppet/parser/functions/num2bool.rb
+++ b/lib/puppet/parser/functions/num2bool.rb
@@ -2,38 +2,41 @@
# num2bool.rb
#
-# TODO(Krzysztof Wilczynski): We probably need to approach numeric values differently ...
-
module Puppet::Parser::Functions
newfunction(:num2bool, :type => :rvalue, :doc => <<-EOS
-This function converts a number into a true boolean. Zero becomes false. Numbers
-higher then 0 become true.
+This function converts a number or a string representation of a number into a
+true boolean. Zero or anything non-numeric becomes false. Numbers higher then 0
+become true.
EOS
) do |arguments|
raise(Puppet::ParseError, "num2bool(): Wrong number of arguments " +
- "given (#{arguments.size} for 1)") if arguments.size < 1
+ "given (#{arguments.size} for 1)") if arguments.size != 1
number = arguments[0]
- # Only numbers allowed ...
- unless number.match(/^\-?\d+$/)
- raise(Puppet::ParseError, 'num2bool(): Requires integer to work with')
+ case number
+ when Numeric
+ # Yay, it's a number
+ when String
+ begin
+ number = Float(number)
+ rescue ArgumentError => ex
+ raise(Puppet::ParseError, "num2bool(): '#{number}' does not look like a number: #{ex.message}")
+ end
+ else
+ begin
+ number = number.to_s
+ rescue NoMethodError => ex
+ raise(Puppet::ParseError, "num2bool(): Unable to parse argument: #{ex.message}")
+ end
end
- result = case number
- when /^0$/
- false
- when /^\-?\d+$/
- # Numbers in Puppet are often string-encoded which is troublesome ...
- number = number.to_i
- # We yield true for any positive number and false otherwise ...
- number > 0 ? true : false
- else
- raise(Puppet::ParseError, 'num2bool(): Unknown numeric format given')
- end
+ # Truncate Floats
+ number = number.to_i
- return result
+ # Return true for any positive number and false otherwise
+ return number > 0
end
end
diff --git a/lib/puppet/parser/functions/parseyaml.rb b/lib/puppet/parser/functions/parseyaml.rb
index e8ac8a4..53d54fa 100644
--- a/lib/puppet/parser/functions/parseyaml.rb
+++ b/lib/puppet/parser/functions/parseyaml.rb
@@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:parseyaml, :type => :rvalue, :doc => <<-EOS
-This function accepts YAML as a string and converts it into the correct
+This function accepts YAML as a string and converts it into the correct
Puppet structure.
EOS
) do |arguments|
diff --git a/lib/puppet/parser/functions/pick.rb b/lib/puppet/parser/functions/pick.rb
new file mode 100644
index 0000000..cbc0300
--- /dev/null
+++ b/lib/puppet/parser/functions/pick.rb
@@ -0,0 +1,29 @@
+module Puppet::Parser::Functions
+ newfunction(:pick, :type => :rvalue, :doc => <<-EOS
+
+This function is similar to a coalesce function in SQL in that it will return
+the first value in a list of values that is not undefined or an empty string
+(two things in Puppet that will return a boolean false value). Typically,
+this function is used to check for a value in the Puppet Dashboard/Enterprise
+Console, and failover to a default value like the following:
+
+ $real_jenkins_version = pick($::jenkins_version, '1.449')
+
+The value of $real_jenkins_version will first look for a top-scope variable
+called 'jenkins_version' (note that parameters set in the Puppet Dashboard/
+Enterprise Console are brought into Puppet as top-scope variables), and,
+failing that, will use a default value of 1.449.
+
+EOS
+) do |args|
+ args = args.compact
+ args.delete(:undef)
+ args.delete(:undefined)
+ args.delete("")
+ if args[0].to_s.empty? then
+ fail "Must provide non empty value."
+ else
+ return args[0]
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/prefix.rb b/lib/puppet/parser/functions/prefix.rb
index 4593976..62211ae 100644
--- a/lib/puppet/parser/functions/prefix.rb
+++ b/lib/puppet/parser/functions/prefix.rb
@@ -6,7 +6,7 @@ module Puppet::Parser::Functions
newfunction(:prefix, :type => :rvalue, :doc => <<-EOS
This function applies a prefix to all elements in an array.
-*Examles:*
+*Examples:*
prefix(['a','b','c'], 'p')
@@ -21,14 +21,14 @@ Will return: ['pa','pb','pc']
array = arguments[0]
unless array.is_a?(Array)
- raise(Puppet::ParseError, 'prefix(): Requires array to work with')
+ raise Puppet::ParseError, "prefix(): expected first argument to be an Array, got #{array.inspect}"
end
prefix = arguments[1] if arguments[1]
if prefix
unless prefix.is_a?(String)
- raise(Puppet::ParseError, 'prefix(): Requires string to work with')
+ raise Puppet::ParseError, "prefix(): expected second argument to be a String, got #{suffix.inspect}"
end
end
diff --git a/lib/puppet/parser/functions/range.rb b/lib/puppet/parser/functions/range.rb
index 03ab9e9..0849491 100644
--- a/lib/puppet/parser/functions/range.rb
+++ b/lib/puppet/parser/functions/range.rb
@@ -15,10 +15,19 @@ an array.
Will return: [0,1,2,3,4,5,6,7,8,9]
+ range("00", "09")
+
+Will return: [0,1,2,3,4,5,6,7,8,9] (Zero padded strings are converted to
+integers automatically)
+
range("a", "c")
Will return: ["a","b","c"]
+ range("host01", "host10")
+
+Will return: ["host01", "host02", ..., "host09", "host10"]
+
Passing a third argument will cause the generated range to step by that
interval, e.g.
diff --git a/lib/puppet/parser/functions/reject.rb b/lib/puppet/parser/functions/reject.rb
new file mode 100644
index 0000000..1953ffc
--- /dev/null
+++ b/lib/puppet/parser/functions/reject.rb
@@ -0,0 +1,31 @@
+#
+# reject.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:reject, :type => :rvalue, :doc => <<-EOS) do |args|
+This function searches through an array and rejects all elements that match
+the provided regular expression.
+
+*Examples:*
+
+ reject(['aaa','bbb','ccc','aaaddd'], 'aaa')
+
+Would return:
+
+ ['bbb','ccc']
+EOS
+
+ if (args.size != 2)
+ raise Puppet::ParseError,
+ "reject(): Wrong number of arguments given #{args.size} for 2"
+ end
+
+ ary = args[0]
+ pattern = Regexp.new(args[1])
+
+ ary.reject { |e| e =~ pattern }
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/squeeze.rb b/lib/puppet/parser/functions/squeeze.rb
index 65c174a..81fadfd 100644
--- a/lib/puppet/parser/functions/squeeze.rb
+++ b/lib/puppet/parser/functions/squeeze.rb
@@ -14,9 +14,9 @@ Returns a new string where runs of the same character that occur in this set are
end
item = arguments[0]
- squeezeval = arguments[1]
+ squeezeval = arguments[1]
- if item.is_a?(Array) then
+ if item.is_a?(Array) then
if squeezeval then
item.collect { |i| i.squeeze(squeezeval) }
else
diff --git a/lib/puppet/parser/functions/str2bool.rb b/lib/puppet/parser/functions/str2bool.rb
index c320da6..fece7a6 100644
--- a/lib/puppet/parser/functions/str2bool.rb
+++ b/lib/puppet/parser/functions/str2bool.rb
@@ -4,7 +4,7 @@
module Puppet::Parser::Functions
newfunction(:str2bool, :type => :rvalue, :doc => <<-EOS
-This converts a string to a boolean. This attempt to convert strings that
+This converts a string to a boolean. This attempt to convert strings that
contain things like: y, 1, t, true to 'true' and strings that contain things
like: 0, f, n, false, no to 'false'.
EOS
@@ -14,6 +14,11 @@ like: 0, f, n, false, no to 'false'.
"given (#{arguments.size} for 1)") if arguments.size < 1
string = arguments[0]
+
+ # If string is already Boolean, return it
+ if !!string == string
+ return string
+ end
unless string.is_a?(String)
raise(Puppet::ParseError, 'str2bool(): Requires either ' +
diff --git a/lib/puppet/parser/functions/str2saltedsha512.rb b/lib/puppet/parser/functions/str2saltedsha512.rb
new file mode 100644
index 0000000..7fe7b01
--- /dev/null
+++ b/lib/puppet/parser/functions/str2saltedsha512.rb
@@ -0,0 +1,32 @@
+#
+# str2saltedsha512.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:str2saltedsha512, :type => :rvalue, :doc => <<-EOS
+This converts a string to a salted-SHA512 password hash (which is used for
+OS X versions >= 10.7). Given any simple string, you will get a hex version
+of a salted-SHA512 password hash that can be inserted into your Puppet
+manifests as a valid password attribute.
+ EOS
+ ) do |arguments|
+ require 'digest/sha2'
+
+ raise(Puppet::ParseError, "str2saltedsha512(): Wrong number of arguments " +
+ "passed (#{arguments.size} but we require 1)") if arguments.size != 1
+
+ password = arguments[0]
+
+ unless password.is_a?(String)
+ raise(Puppet::ParseError, 'str2saltedsha512(): Requires a ' +
+ "String argument, you passed: #{password.class}")
+ end
+
+ seedint = rand(2**31 - 1)
+ seedstring = Array(seedint).pack("L")
+ saltedpass = Digest::SHA512.digest(seedstring + password)
+ (seedstring + saltedpass).unpack('H*')[0]
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/suffix.rb b/lib/puppet/parser/functions/suffix.rb
new file mode 100644
index 0000000..f7792d6
--- /dev/null
+++ b/lib/puppet/parser/functions/suffix.rb
@@ -0,0 +1,45 @@
+#
+# suffix.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:suffix, :type => :rvalue, :doc => <<-EOS
+This function applies a suffix to all elements in an array.
+
+*Examples:*
+
+ suffix(['a','b','c'], 'p')
+
+Will return: ['ap','bp','cp']
+ EOS
+ ) do |arguments|
+
+ # Technically we support two arguments but only first is mandatory ...
+ raise(Puppet::ParseError, "suffix(): Wrong number of arguments " +
+ "given (#{arguments.size} for 1)") if arguments.size < 1
+
+ array = arguments[0]
+
+ unless array.is_a?(Array)
+ raise Puppet::ParseError, "suffix(): expected first argument to be an Array, got #{array.inspect}"
+ end
+
+ suffix = arguments[1] if arguments[1]
+
+ if suffix
+ unless suffix.is_a? String
+ raise Puppet::ParseError, "suffix(): expected second argument to be a String, got #{suffix.inspect}"
+ end
+ end
+
+ # Turn everything into string same as join would do ...
+ result = array.collect do |i|
+ i = i.to_s
+ suffix ? i + suffix : i
+ end
+
+ return result
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/to_bytes.rb b/lib/puppet/parser/functions/to_bytes.rb
new file mode 100644
index 0000000..8ff73d1
--- /dev/null
+++ b/lib/puppet/parser/functions/to_bytes.rb
@@ -0,0 +1,28 @@
+module Puppet::Parser::Functions
+ newfunction(:to_bytes, :type => :rvalue, :doc => <<-EOS
+ Converts the argument into bytes, for example 4 kB becomes 4096.
+ Takes a single string value as an argument.
+ EOS
+ ) do |arguments|
+
+ raise(Puppet::ParseError, "to_bytes(): Wrong number of arguments " +
+ "given (#{arguments.size} for 1)") if arguments.size != 1
+
+ arg = arguments[0]
+
+ return arg if arg.is_a? Numeric
+
+ value,prefix = */([0-9.e+-]*)\s*([^bB]?)/.match(arg)[1,2]
+
+ value = value.to_f
+ case prefix
+ when '' then return value.to_i
+ when 'k' then return (value*(1<<10)).to_i
+ when 'M' then return (value*(1<<20)).to_i
+ when 'G' then return (value*(1<<30)).to_i
+ when 'T' then return (value*(1<<40)).to_i
+ when 'E' then return (value*(1<<50)).to_i
+ else raise Puppet::ParseError, "to_bytes(): Unknown prefix #{prefix}"
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/union.rb b/lib/puppet/parser/functions/union.rb
new file mode 100644
index 0000000..c91bb80
--- /dev/null
+++ b/lib/puppet/parser/functions/union.rb
@@ -0,0 +1,34 @@
+#
+# union.rb
+#
+
+module Puppet::Parser::Functions
+ newfunction(:union, :type => :rvalue, :doc => <<-EOS
+This function returns a union of two arrays.
+
+*Examples:*
+
+ union(["a","b","c"],["b","c","d"])
+
+Would return: ["a","b","c","d"]
+ EOS
+ ) do |arguments|
+
+ # Two arguments are required
+ raise(Puppet::ParseError, "union(): Wrong number of arguments " +
+ "given (#{arguments.size} for 2)") if arguments.size != 2
+
+ first = arguments[0]
+ second = arguments[1]
+
+ unless first.is_a?(Array) && second.is_a?(Array)
+ raise(Puppet::ParseError, 'union(): Requires 2 arrays')
+ end
+
+ result = first | second
+
+ return result
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/uriescape.rb b/lib/puppet/parser/functions/uriescape.rb
new file mode 100644
index 0000000..67b93a6
--- /dev/null
+++ b/lib/puppet/parser/functions/uriescape.rb
@@ -0,0 +1,36 @@
+#
+# uriescape.rb
+#
+require 'uri'
+
+module Puppet::Parser::Functions
+ newfunction(:uriescape, :type => :rvalue, :doc => <<-EOS
+ Urlencodes a string or array of strings.
+ Requires either a single string or an array as an input.
+ EOS
+ ) do |arguments|
+
+ raise(Puppet::ParseError, "uriescape(): Wrong number of arguments " +
+ "given (#{arguments.size} for 1)") if arguments.size < 1
+
+ value = arguments[0]
+ klass = value.class
+ unsafe = ":/?#[]@!$&'()*+,;= "
+
+ unless [Array, String].include?(klass)
+ raise(Puppet::ParseError, 'uriescape(): Requires either ' +
+ 'array or string to work with')
+ end
+
+ if value.is_a?(Array)
+ # Numbers in Puppet are often string-encoded which is troublesome ...
+ result = value.collect { |i| i.is_a?(String) ? URI.escape(i,unsafe) : i }
+ else
+ result = URI.escape(value,unsafe)
+ end
+
+ return result
+ end
+end
+
+# vim: set ts=2 sw=2 et :
diff --git a/lib/puppet/parser/functions/validate_absolute_path.rb b/lib/puppet/parser/functions/validate_absolute_path.rb
new file mode 100644
index 0000000..fe27974
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_absolute_path.rb
@@ -0,0 +1,56 @@
+module Puppet::Parser::Functions
+ newfunction(:validate_absolute_path, :doc => <<-'ENDHEREDOC') do |args|
+ Validate the string represents an absolute path in the filesystem. This function works
+ for windows and unix style paths.
+
+ The following values will pass:
+
+ $my_path = "C:/Program Files (x86)/Puppet Labs/Puppet"
+ validate_absolute_path($my_path)
+ $my_path2 = "/var/lib/puppet"
+ validate_absolute_path($my_path2)
+
+
+ The following values will fail, causing compilation to abort:
+
+ validate_absolute_path(true)
+ validate_absolute_path([ 'var/lib/puppet', '/var/foo' ])
+ validate_absolute_path([ '/var/lib/puppet', 'var/foo' ])
+ $undefined = undef
+ validate_absolute_path($undefined)
+
+ ENDHEREDOC
+
+ require 'puppet/util'
+
+ unless args.length > 0 then
+ raise Puppet::ParseError, ("validate_absolute_path(): wrong number of arguments (#{args.length}; must be > 0)")
+ end
+
+ args.each do |arg|
+ # This logic was borrowed from
+ # [lib/puppet/file_serving/base.rb](https://github.com/puppetlabs/puppet/blob/master/lib/puppet/file_serving/base.rb)
+
+ # Puppet 2.7 and beyond will have Puppet::Util.absolute_path? Fall back to a back-ported implementation otherwise.
+ if Puppet::Util.respond_to?(:absolute_path?) then
+ unless Puppet::Util.absolute_path?(arg, :posix) or Puppet::Util.absolute_path?(arg, :windows)
+ raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
+ end
+ else
+ # This code back-ported from 2.7.x's lib/puppet/util.rb Puppet::Util.absolute_path?
+ # Determine in a platform-specific way whether a path is absolute. This
+ # defaults to the local platform if none is specified.
+ # Escape once for the string literal, and once for the regex.
+ slash = '[\\\\/]'
+ name = '[^\\\\/]+'
+ regexes = {
+ :windows => %r!^(([A-Z]:#{slash})|(#{slash}#{slash}#{name}#{slash}#{name})|(#{slash}#{slash}\?#{slash}#{name}))!i,
+ :posix => %r!^/!,
+ }
+
+ rval = (!!(arg =~ regexes[:posix])) || (!!(arg =~ regexes[:windows]))
+ rval or raise Puppet::ParseError, ("#{arg.inspect} is not an absolute path.")
+ end
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/validate_array.rb b/lib/puppet/parser/functions/validate_array.rb
index a7a7165..34b5118 100644
--- a/lib/puppet/parser/functions/validate_array.rb
+++ b/lib/puppet/parser/functions/validate_array.rb
@@ -1,17 +1,15 @@
module Puppet::Parser::Functions
newfunction(:validate_array, :doc => <<-'ENDHEREDOC') do |args|
- Validate all passed values are a Array data structure
- value does not pass the check.
+ Validate that all passed values are array data structures. Abort catalog
+ compilation if any value fails this check.
- Example:
-
- These values validate
+ The following values will pass:
$my_array = [ 'one', 'two' ]
validate_array($my_array)
- These values do NOT validate
+ The following values will fail, causing compilation to abort:
validate_array(true)
validate_array('some_string')
diff --git a/lib/puppet/parser/functions/validate_augeas.rb b/lib/puppet/parser/functions/validate_augeas.rb
new file mode 100644
index 0000000..154d660
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_augeas.rb
@@ -0,0 +1,81 @@
+module Puppet::Parser::Functions
+ newfunction(:validate_augeas, :doc => <<-'ENDHEREDOC') do |args|
+ Perform validation of a string using an Augeas lens
+ The first argument of this function should be a string to
+ test, and the second argument should be the name of the Augeas lens to use.
+ If Augeas fails to parse the string with the lens, the compilation will
+ abort with a parse error.
+
+ A third argument can be specified, listing paths which should
+ not be found in the file. The `$file` variable points to the location
+ of the temporary file being tested in the Augeas tree.
+
+ For example, if you want to make sure your passwd content never contains
+ a user `foo`, you could write:
+
+ validate_augeas($passwdcontent, 'Passwd.lns', ['$file/foo'])
+
+ Or if you wanted to ensure that no users used the '/bin/barsh' shell,
+ you could use:
+
+ validate_augeas($passwdcontent, 'Passwd.lns', ['$file/*[shell="/bin/barsh"]']
+
+ If a fourth argument is specified, this will be the error message raised and
+ seen by the user.
+
+ A helpful error message can be returned like this:
+
+ validate_augeas($sudoerscontent, 'Sudoers.lns', [], 'Failed to validate sudoers content with Augeas')
+
+ ENDHEREDOC
+ unless Puppet.features.augeas?
+ raise Puppet::ParseError, ("validate_augeas(): this function requires the augeas feature. See http://projects.puppetlabs.com/projects/puppet/wiki/Puppet_Augeas#Pre-requisites for how to activate it.")
+ end
+
+ if (args.length < 2) or (args.length > 4) then
+ raise Puppet::ParseError, ("validate_augeas(): wrong number of arguments (#{args.length}; must be 2, 3, or 4)")
+ end
+
+ msg = args[3] || "validate_augeas(): Failed to validate content against #{args[1].inspect}"
+
+ require 'augeas'
+ aug = Augeas::open(nil, nil, Augeas::NO_MODL_AUTOLOAD)
+ begin
+ content = args[0]
+
+ # Test content in a temporary file
+ tmpfile = Tempfile.new("validate_augeas")
+ begin
+ tmpfile.write(content)
+ ensure
+ tmpfile.close
+ end
+
+ # Check for syntax
+ lens = args[1]
+ aug.transform(
+ :lens => lens,
+ :name => 'Validate_augeas',
+ :incl => tmpfile.path
+ )
+ aug.load!
+
+ unless aug.match("/augeas/files#{tmpfile.path}//error").empty?
+ error = aug.get("/augeas/files#{tmpfile.path}//error/message")
+ msg += " with error: #{error}"
+ raise Puppet::ParseError, (msg)
+ end
+
+ # Launch unit tests
+ tests = args[2] || []
+ aug.defvar('file', "/files#{tmpfile.path}")
+ tests.each do |t|
+ msg += " testing path #{t}"
+ raise Puppet::ParseError, (msg) unless aug.match(t).empty?
+ end
+ ensure
+ aug.close
+ tmpfile.unlink
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/validate_bool.rb b/lib/puppet/parser/functions/validate_bool.rb
index 49e6378..62c1d88 100644
--- a/lib/puppet/parser/functions/validate_bool.rb
+++ b/lib/puppet/parser/functions/validate_bool.rb
@@ -1,27 +1,22 @@
module Puppet::Parser::Functions
newfunction(:validate_bool, :doc => <<-'ENDHEREDOC') do |args|
- Validate all passed values are true or false. Abort catalog compilation if the
- value does not pass the check.
+ Validate that all passed values are either true or false. Abort catalog
+ compilation if any value fails this check.
- Example:
-
- These booleans validate
+ The following values will pass:
$iamtrue = true
validate_bool(true)
validate_bool(true, true, false, $iamtrue)
- These strings do NOT validate and will abort catalog compilation
+ The following values will fail, causing compilation to abort:
$some_array = [ true ]
validate_bool("false")
validate_bool("true")
validate_bool($some_array)
- * Jeff McCune <jeff@puppetlabs.com>
- * Dan Bode <dan@puppetlabs.com>
-
ENDHEREDOC
unless args.length > 0 then
diff --git a/lib/puppet/parser/functions/validate_cmd.rb b/lib/puppet/parser/functions/validate_cmd.rb
new file mode 100644
index 0000000..344a80c
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_cmd.rb
@@ -0,0 +1,47 @@
+require 'puppet/util/execution'
+
+module Puppet::Parser::Functions
+ newfunction(:validate_cmd, :doc => <<-'ENDHEREDOC') do |args|
+ Perform validation of a string with an external command.
+ The first argument of this function should be a string to
+ test, and the second argument should be a path to a test command
+ taking a file as last argument. If the command, launched against
+ a tempfile containing the passed string, returns a non-null value,
+ compilation will abort with a parse error.
+
+ If a third argument is specified, this will be the error message raised and
+ seen by the user.
+
+ A helpful error message can be returned like this:
+
+ Example:
+
+ validate_cmd($sudoerscontent, '/usr/sbin/visudo -c -f', 'Visudo failed to validate sudoers content')
+
+ ENDHEREDOC
+ if (args.length < 2) or (args.length > 3) then
+ raise Puppet::ParseError, ("validate_cmd(): wrong number of arguments (#{args.length}; must be 2 or 3)")
+ end
+
+ msg = args[2] || "validate_cmd(): failed to validate content with command #{args[1].inspect}"
+
+ content = args[0]
+ checkscript = args[1]
+
+ # Test content in a temporary file
+ tmpfile = Tempfile.new("validate_cmd")
+ begin
+ tmpfile.write(content)
+ if Puppet::Util::Execution.respond_to?('execute')
+ Puppet::Util::Execution.execute("#{checkscript} #{tmpfile.path}")
+ else
+ Puppet::Util.execute("#{checkscript} #{tmpfile.path}")
+ end
+ rescue Puppet::ExecutionFailure => detail
+ msg += "\n#{detail}"
+ raise Puppet::ParseError, msg
+ ensure
+ tmpfile.unlink
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/validate_hash.rb b/lib/puppet/parser/functions/validate_hash.rb
index 1443318..9bdd543 100644
--- a/lib/puppet/parser/functions/validate_hash.rb
+++ b/lib/puppet/parser/functions/validate_hash.rb
@@ -1,25 +1,21 @@
module Puppet::Parser::Functions
newfunction(:validate_hash, :doc => <<-'ENDHEREDOC') do |args|
- Validate all passed values are a Hash data structure
- value does not pass the check.
+ Validate that all passed values are hash data structures. Abort catalog
+ compilation if any value fails this check.
- Example:
-
- These values validate
+ The following values will pass:
$my_hash = { 'one' => 'two' }
validate_hash($my_hash)
- These values do NOT validate
+ The following values will fail, causing compilation to abort:
validate_hash(true)
validate_hash('some_string')
$undefined = undef
validate_hash($undefined)
- * Jeff McCune <jeff@puppetlabs.com>
-
ENDHEREDOC
unless args.length > 0 then
diff --git a/lib/puppet/parser/functions/validate_re.rb b/lib/puppet/parser/functions/validate_re.rb
index 583f26a..ca25a70 100644
--- a/lib/puppet/parser/functions/validate_re.rb
+++ b/lib/puppet/parser/functions/validate_re.rb
@@ -1,35 +1,40 @@
module Puppet::Parser::Functions
-
newfunction(:validate_re, :doc => <<-'ENDHEREDOC') do |args|
- Perform simple validation of a string against a regular expression. The second
- argument of the function should be a string regular expression (without the //'s)
- or an array of regular expressions. If none of the regular expressions in the array
- match the string passed in, then an exception will be raised.
+ Perform simple validation of a string against one or more regular
+ expressions. The first argument of this function should be a string to
+ test, and the second argument should be a stringified regular expression
+ (without the // delimiters) or an array of regular expressions. If none
+ of the regular expressions match the string passed in, compilation will
+ abort with a parse error.
- Example:
+ If a third argument is specified, this will be the error message raised and
+ seen by the user.
- These strings validate against the regular expressions
+ The following strings will validate against the regular expressions:
validate_re('one', '^one$')
validate_re('one', [ '^one', '^two' ])
- These strings do NOT validate
+ The following strings will fail to validate, causing compilation to abort:
validate_re('one', [ '^two', '^three' ])
- Jeff McCune <jeff@puppetlabs.com>
+ A helpful error message can be returned like this:
+
+ validate_re($::puppetversion, '^2.7', 'The $puppetversion fact value does not match 2.7')
ENDHEREDOC
- if args.length != 2 then
- raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2)")
+ if (args.length < 2) or (args.length > 3) then
+ raise Puppet::ParseError, ("validate_re(): wrong number of arguments (#{args.length}; must be 2 or 3)")
end
- msg = "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
+ msg = args[2] || "validate_re(): #{args[0].inspect} does not match #{args[1].inspect}"
- raise Puppet::ParseError, (msg) unless args[1].any? do |re_str|
+ # We're using a flattened array here because we can't call String#any? in
+ # Ruby 1.9 like we can in Ruby 1.8
+ raise Puppet::ParseError, (msg) unless [args[1]].flatten.any? do |re_str|
args[0] =~ Regexp.compile(re_str)
end
end
-
end
diff --git a/lib/puppet/parser/functions/validate_slength.rb b/lib/puppet/parser/functions/validate_slength.rb
new file mode 100644
index 0000000..fdcc0a2
--- /dev/null
+++ b/lib/puppet/parser/functions/validate_slength.rb
@@ -0,0 +1,52 @@
+module Puppet::Parser::Functions
+
+ newfunction(:validate_slength, :doc => <<-'ENDHEREDOC') do |args|
+ Validate that the first argument is a string (or an array of strings), and
+ less/equal to than the length of the second argument. It fails if the first
+ argument is not a string or array of strings, and if arg 2 is not convertable
+ to a number.
+
+ The following values will pass:
+
+ validate_slength("discombobulate",17)
+ validate_slength(["discombobulate","moo"],17)
+
+ The following valueis will not:
+
+ validate_slength("discombobulate",1)
+ validate_slength(["discombobulate","thermometer"],5)
+
+ ENDHEREDOC
+
+ raise Puppet::ParseError, ("validate_slength(): Wrong number of arguments (#{args.length}; must be = 2)") unless args.length == 2
+
+ unless (args[0].is_a?(String) or args[0].is_a?(Array))
+ raise Puppet::ParseError, ("validate_slength(): please pass a string, or an array of strings - what you passed didn't work for me at all - #{args[0].class}")
+ end
+
+ begin
+ max_length = args[1].to_i
+ rescue NoMethodError => e
+ raise Puppet::ParseError, ("validate_slength(): Couldn't convert whatever you passed as the length parameter to an integer - sorry: " + e.message )
+ end
+
+ raise Puppet::ParseError, ("validate_slength(): please pass a positive number as max_length") unless max_length > 0
+
+ case args[0]
+ when String
+ raise Puppet::ParseError, ("validate_slength(): #{args[0].inspect} is #{args[0].length} characters. It should have been less than or equal to #{max_length} characters") unless args[0].length <= max_length
+ when Array
+ args[0].each do |arg|
+ if arg.is_a?(String)
+ unless ( arg.is_a?(String) and arg.length <= max_length )
+ raise Puppet::ParseError, ("validate_slength(): #{arg.inspect} is #{arg.length} characters. It should have been less than or equal to #{max_length} characters")
+ end
+ else
+ raise Puppet::ParseError, ("validate_slength(): #{arg.inspect} is not a string, it's a #{arg.class}")
+ end
+ end
+ else
+ raise Puppet::ParseError, ("validate_slength(): please pass a string, or an array of strings - what you passed didn't work for me at all - #{args[0].class}")
+ end
+ end
+end
diff --git a/lib/puppet/parser/functions/validate_string.rb b/lib/puppet/parser/functions/validate_string.rb
index d0e1376..e667794 100644
--- a/lib/puppet/parser/functions/validate_string.rb
+++ b/lib/puppet/parser/functions/validate_string.rb
@@ -1,17 +1,15 @@
module Puppet::Parser::Functions
newfunction(:validate_string, :doc => <<-'ENDHEREDOC') do |args|
- Validate all passed values are a string data structure
- value does not pass the check.
+ Validate that all passed values are string data structures. Abort catalog
+ compilation if any value fails this check.
- Example:
-
- These values validate
+ The following values will pass:
$my_string = "one two"
- validate_string($my_string)
+ validate_string($my_string, 'three')
- These values do NOT validate
+ The following values will fail, causing compilation to abort:
validate_string(true)
validate_string([ 'some', 'array' ])
diff --git a/lib/puppet/provider/file_line/ruby.rb b/lib/puppet/provider/file_line/ruby.rb
index 63bbd8e..a3219d3 100644
--- a/lib/puppet/provider/file_line/ruby.rb
+++ b/lib/puppet/provider/file_line/ruby.rb
@@ -1,15 +1,59 @@
+
Puppet::Type.type(:file_line).provide(:ruby) do
def exists?
- File.readlines(resource[:path]).find do |line|
+ lines.find do |line|
line.chomp == resource[:line].chomp
end
end
def create
+ if resource[:match]
+ handle_create_with_match()
+ else
+ handle_create_without_match()
+ end
+ end
+
+ def destroy
+ local_lines = lines
+ File.open(resource[:path],'w') do |fh|
+ fh.write(local_lines.reject{|l| l.chomp == resource[:line] }.join(''))
+ end
+ end
+
+ private
+ def lines
+ # If this type is ever used with very large files, we should
+ # write this in a different way, using a temp
+ # file; for now assuming that this type is only used on
+ # small-ish config files that can fit into memory without
+ # too much trouble.
+ @lines ||= File.readlines(resource[:path])
+ end
+
+ def handle_create_with_match()
+ regex = resource[:match] ? Regexp.new(resource[:match]) : nil
+ match_count = lines.select { |l| regex.match(l) }.size
+ if match_count > 1
+ raise Puppet::Error, "More than one line in file '#{resource[:path]}' matches pattern '#{resource[:match]}'"
+ end
+ File.open(resource[:path], 'w') do |fh|
+ lines.each do |l|
+ fh.puts(regex.match(l) ? resource[:line] : l)
+ end
+
+ if (match_count == 0)
+ fh.puts(resource[:line])
+ end
+ end
+ end
+
+ def handle_create_without_match
File.open(resource[:path], 'a') do |fh|
fh.puts resource[:line]
end
end
+
end
diff --git a/lib/puppet/type/anchor.rb b/lib/puppet/type/anchor.rb
index 0c28b1c..fe1e5aa 100644
--- a/lib/puppet/type/anchor.rb
+++ b/lib/puppet/type/anchor.rb
@@ -2,23 +2,32 @@ Puppet::Type.newtype(:anchor) do
desc <<-'ENDOFDESC'
A simple resource type intended to be used as an anchor in a composite class.
+ In Puppet 2.6, when a class declares another class, the resources in the
+ interior class are not contained by the exterior class. This interacts badly
+ with the pattern of composing complex modules from smaller classes, as it
+ makes it impossible for end users to specify order relationships between the
+ exterior class and other modules.
+
+ The anchor type lets you work around this. By sandwiching any interior
+ classes between two no-op resources that _are_ contained by the exterior
+ class, you can ensure that all resources in the module are contained.
+
class ntp {
+ # These classes will have the correct order relationship with each
+ # other. However, without anchors, they won't have any order
+ # relationship to Class['ntp'].
class { 'ntp::package': }
-> class { 'ntp::config': }
-> class { 'ntp::service': }
- # These two resources "anchor" the composed classes
- # such that the end user may use "require" and "before"
- # relationships with Class['ntp']
- anchor { 'ntp::begin': } -> class { 'ntp::package': }
- class { 'ntp::service': } -> anchor { 'ntp::end': }
+ # These two resources "anchor" the composed classes within the ntp
+ # class.
+ anchor { 'ntp::begin': } -> Class['ntp::package']
+ Class['ntp::service'] -> anchor { 'ntp::end': }
}
- This resource allows all of the classes in the ntp module to be contained
- within the ntp class from a dependency management point of view.
-
This allows the end user of the ntp module to establish require and before
- relationships easily:
+ relationships with Class['ntp']:
class { 'ntp': } -> class { 'mcollective': }
class { 'mcollective': } -> class { 'ntp': }
@@ -29,4 +38,9 @@ Puppet::Type.newtype(:anchor) do
desc "The name of the anchor resource."
end
+ def refresh
+ # We don't do anything with them, but we need this to
+ # show that we are "refresh aware" and not break the
+ # chain of propagation.
+ end
end
diff --git a/lib/puppet/type/file_line.rb b/lib/puppet/type/file_line.rb
index aacd6d9..f71a4bc 100644
--- a/lib/puppet/type/file_line.rb
+++ b/lib/puppet/type/file_line.rb
@@ -1,34 +1,48 @@
Puppet::Type.newtype(:file_line) do
desc <<-EOT
- Type that can append whole a line to a file if it does not already contain it.
+ Ensures that a given line is contained within a file. The implementation
+ matches the full line, including whitespace at the beginning and end. If
+ the line is not contained in the given file, Puppet will add the line to
+ ensure the desired state. Multiple resources may be declared to manage
+ multiple lines in the same file.
- Example:
+ Example:
- file_line { 'sudo_rule':
- path => '/etc/sudoers',
- line => '%admin ALL=(ALL) ALL',
- }
+ file_line { 'sudo_rule':
+ path => '/etc/sudoers',
+ line => '%sudo ALL=(ALL) ALL',
+ }
+ file_line { 'sudo_rule_nopw':
+ path => '/etc/sudoers',
+ line => '%sudonopw ALL=(ALL) NOPASSWD: ALL',
+ }
+
+ In this example, Puppet will ensure both of the specified lines are
+ contained in the file /etc/sudoers.
EOT
ensurable do
+ defaultvalues
defaultto :present
- newvalue(:present) do
- provider.create
- end
end
newparam(:name, :namevar => true) do
- desc 'arbitrary name used as identity'
+ desc 'An arbitrary name used as the identity of the resource.'
+ end
+
+ newparam(:match) do
+ desc 'An optional regular expression to run against existing lines in the file;\n' +
+ 'if a match is found, we replace that line rather than adding a new line.'
end
newparam(:line) do
- desc 'The line to be appended to the path.'
+ desc 'The line to be appended to the file located by the path parameter.'
end
newparam(:path) do
- desc 'File to possibly append a line to.'
+ desc 'The file Puppet will ensure contains the line specified by the line parameter.'
validate do |value|
unless (Puppet.features.posix? and value =~ /^\//) or (Puppet.features.microsoft_windows? and (value =~ /^.:\// or value =~ /^\/\/[^\/]+\/[^\/]+/))
raise(Puppet::Error, "File paths must be fully qualified, not '#{value}'")
@@ -36,9 +50,21 @@ Puppet::Type.newtype(:file_line) do
end
end
+ # Autorequire the file resource if it's being managed
+ autorequire(:file) do
+ self[:path]
+ end
+
validate do
unless self[:line] and self[:path]
raise(Puppet::Error, "Both line and path are required attributes")
end
+
+ if (self[:match])
+ unless Regexp.new(self[:match]).match(self[:line])
+ raise(Puppet::Error, "When providing a 'match' parameter, the value must be a regex that matches against the value of your 'line' parameter")
+ end
+ end
+
end
end
diff --git a/manifests/init.pp b/manifests/init.pp
index c804568..500ad77 100644
--- a/manifests/init.pp
+++ b/manifests/init.pp
@@ -1,16 +1,18 @@
# Class: stdlib
#
-# This module manages stdlib
+# This module manages stdlib. Most of stdlib's features are automatically
+# loaded by Puppet, but this class should be declared in order to use the
+# standardized run stages.
#
-# Parameters:
+# Parameters: none
#
# Actions:
#
-# Requires:
+# Declares all other classes in the stdlib module. Currently, this consists
+# of stdlib::stages.
#
-# Sample Usage:
+# Requires: nothing
#
-# [Remember: No empty lines between comments and class definition]
class stdlib {
class { 'stdlib::stages': }
diff --git a/manifests/stages.pp b/manifests/stages.pp
index 365b905..eb15fd6 100644
--- a/manifests/stages.pp
+++ b/manifests/stages.pp
@@ -1,8 +1,9 @@
# Class: stdlib::stages
#
-# This class manages a standard set of Run Stages for Puppet.
+# This class manages a standard set of run stages for Puppet. It is managed by
+# the stdlib class, and should not be declared independently.
#
-# The high level stages are (In order):
+# The high level stages are (in order):
#
# * setup
# * main
@@ -13,19 +14,19 @@
# * deploy_app
# * deploy
#
-# Parameters:
+# Parameters: none
#
# Actions:
#
# Declares various run-stages for deploying infrastructure,
# language runtimes, and application layers.
#
-# Requires:
+# Requires: nothing
#
# Sample Usage:
#
# node default {
-# include stdlib::stages
+# include stdlib
# class { java: stage => 'runtime' }
# }
#
diff --git a/spec/classes/anchor_spec.rb b/spec/classes/anchor_spec.rb
new file mode 100644
index 0000000..2dd17de
--- /dev/null
+++ b/spec/classes/anchor_spec.rb
@@ -0,0 +1,32 @@
+require 'puppet'
+require 'rspec-puppet'
+
+describe "anchorrefresh" do
+ let(:node) { 'testhost.example.com' }
+ let :pre_condition do
+ <<-ANCHORCLASS
+class anchored {
+ anchor { 'anchored::begin': }
+ ~> anchor { 'anchored::end': }
+}
+
+class anchorrefresh {
+ notify { 'first': }
+ ~> class { 'anchored': }
+ ~> anchor { 'final': }
+}
+ ANCHORCLASS
+ end
+
+ def apply_catalog_and_return_exec_rsrc
+ catalog = subject.to_ral
+ transaction = catalog.apply
+ transaction.resource_status("Anchor[final]")
+ end
+
+ it 'propagates events through the anchored class' do
+ resource = apply_catalog_and_return_exec_rsrc
+
+ expect(resource.restarted).to eq(true)
+ end
+end
diff --git a/spec/functions/defined_with_params_spec.rb b/spec/functions/defined_with_params_spec.rb
new file mode 100644
index 0000000..28dbab3
--- /dev/null
+++ b/spec/functions/defined_with_params_spec.rb
@@ -0,0 +1,37 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+require 'rspec-puppet'
+describe 'defined_with_params' do
+ describe 'when a resource is not specified' do
+ it { should run.with_params().and_raise_error(ArgumentError) }
+ end
+ describe 'when compared against a resource with no attributes' do
+ let :pre_condition do
+ 'user { "dan": }'
+ end
+ it do
+ should run.with_params('User[dan]', {}).and_return(true)
+ should run.with_params('User[bob]', {}).and_return(false)
+ should run.with_params('User[dan]', {'foo' => 'bar'}).and_return(false)
+ end
+ end
+
+ describe 'when compared against a resource with attributes' do
+ let :pre_condition do
+ 'user { "dan": ensure => present, shell => "/bin/csh", managehome => false}'
+ end
+ it do
+ should run.with_params('User[dan]', {}).and_return(true)
+ should run.with_params('User[dan]', '').and_return(true)
+ should run.with_params('User[dan]', {'ensure' => 'present'}
+ ).and_return(true)
+ should run.with_params('User[dan]',
+ {'ensure' => 'present', 'managehome' => false}
+ ).and_return(true)
+ should run.with_params('User[dan]',
+ {'ensure' => 'absent', 'managehome' => false}
+ ).and_return(false)
+ end
+ end
+end
diff --git a/spec/functions/ensure_packages_spec.rb b/spec/functions/ensure_packages_spec.rb
new file mode 100644
index 0000000..1c2a328
--- /dev/null
+++ b/spec/functions/ensure_packages_spec.rb
@@ -0,0 +1,42 @@
+#! /usr/bin/env ruby
+
+require 'spec_helper'
+require 'rspec-puppet'
+
+describe 'ensure_packages' do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ describe 'argument handling' do
+ it 'fails with no arguments' do
+ should run.with_params().and_raise_error(Puppet::ParseError)
+ end
+ it 'requires an array' do
+ lambda { scope.function_ensure_packages([['foo']]) }.should_not raise_error
+ end
+ it 'fails when given a string' do
+ should run.with_params('foo').and_raise_error(Puppet::ParseError)
+ end
+ end
+
+ context 'given a catalog containing Package[puppet]{ensure => absent}' do
+ let :pre_condition do
+ 'package { puppet: ensure => absent }'
+ end
+
+ # NOTE: should run.with_params has the side effect of making the compiler
+ # available to the test harness.
+ it 'has no effect on Package[puppet]' do
+ should run.with_params(['puppet'])
+ rsrc = compiler.catalog.resource('Package[puppet]')
+ rsrc.to_hash.should == {:ensure => "absent"}
+ end
+ end
+
+ context 'given a clean catalog' do
+ it 'declares package resources with ensure => present' do
+ should run.with_params(['facter'])
+ rsrc = compiler.catalog.resource('Package[facter]')
+ rsrc.to_hash.should == {:name => "facter", :ensure => "present"}
+ end
+ end
+end
diff --git a/spec/functions/ensure_resource_spec.rb b/spec/functions/ensure_resource_spec.rb
new file mode 100644
index 0000000..2e8aefc
--- /dev/null
+++ b/spec/functions/ensure_resource_spec.rb
@@ -0,0 +1,64 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+require 'rspec-puppet'
+describe 'ensure_resource' do
+ describe 'when a type or title is not specified' do
+ it { should run.with_params().and_raise_error(ArgumentError) }
+ it { should run.with_params(['type']).and_raise_error(ArgumentError) }
+ end
+
+ describe 'when compared against a resource with no attributes' do
+ let :pre_condition do
+ 'user { "dan": }'
+ end
+ it "should contain the the ensured resources" do
+ subject.should run.with_params('user', 'dan', {})
+ compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]'
+ end
+ end
+
+ describe 'when compared against a resource with attributes' do
+ let :pre_condition do
+ 'user { "dan": ensure => present, shell => "/bin/csh", managehome => false}'
+ end
+ # these first three should not fail
+ it { should run.with_params('User', 'dan', {}) }
+ it { should run.with_params('User', 'dan', '') }
+ it { should run.with_params('User', 'dan', {'ensure' => 'present'}) }
+ it { should run.with_params('User', 'dan', {'ensure' => 'present', 'managehome' => false}) }
+ # test that this fails
+ it { should run.with_params('User', 'dan', {'ensure' => 'absent', 'managehome' => false}).and_raise_error(Puppet::Error) }
+ end
+
+ describe 'when an array of new resources are passed in' do
+ it "should contain the ensured resources" do
+ subject.should run.with_params('User', ['dan', 'alex'], {})
+ compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]'
+ compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]'
+ end
+ end
+
+ describe 'when an array of existing resources is compared against existing resources' do
+ let :pre_condition do
+ 'user { "dan": ensure => present; "alex": ensure => present }'
+ end
+ it "should return the existing resources" do
+ subject.should run.with_params('User', ['dan', 'alex'], {})
+ compiler.catalog.resource('User[dan]').to_s.should == 'User[dan]'
+ compiler.catalog.resource('User[alex]').to_s.should == 'User[alex]'
+ end
+ end
+
+ describe 'when compared against existing resources with attributes' do
+ let :pre_condition do
+ 'user { "dan": ensure => present; "alex": ensure => present }'
+ end
+ # These should not fail
+ it { should run.with_params('User', ['dan', 'alex'], {}) }
+ it { should run.with_params('User', ['dan', 'alex'], '') }
+ it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'present'}) }
+ # This should fail
+ it { should run.with_params('User', ['dan', 'alex'], {'ensure' => 'absent'}).and_raise_error(Puppet::Error) }
+ end
+end
diff --git a/spec/functions/getparam_spec.rb b/spec/functions/getparam_spec.rb
new file mode 100644
index 0000000..d9c50a6
--- /dev/null
+++ b/spec/functions/getparam_spec.rb
@@ -0,0 +1,34 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+require 'rspec-puppet'
+describe 'getparam' do
+ describe 'when a resource is not specified' do
+ it do
+ should run.with_params().and_raise_error(ArgumentError)
+ should run.with_params('User[dan]').and_raise_error(ArgumentError)
+ should run.with_params('User[dan]', {}).and_raise_error(ArgumentError)
+ should run.with_params('User[dan]', '').and_return('')
+ end
+ end
+ describe 'when compared against a resource with no params' do
+ let :pre_condition do
+ 'user { "dan": }'
+ end
+ it do
+ should run.with_params('User[dan]', 'shell').and_return('')
+ end
+ end
+
+ describe 'when compared against a resource with params' do
+ let :pre_condition do
+ 'user { "dan": ensure => present, shell => "/bin/sh", managehome => false}'
+ end
+ it do
+ should run.with_params('User[dan]', 'shell').and_return('/bin/sh')
+ should run.with_params('User[dan]', '').and_return('')
+ should run.with_params('User[dan]', 'ensure').and_return('present')
+ should run.with_params('User[dan]', 'managehome').and_return(false)
+ end
+ end
+end
diff --git a/spec/lib/puppet_spec/files.rb b/spec/lib/puppet_spec/files.rb
deleted file mode 100755
index 30fb4fc..0000000
--- a/spec/lib/puppet_spec/files.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require 'fileutils'
-require 'tempfile'
-
-# A support module for testing files.
-module PuppetSpec::Files
- # This code exists only to support tests that run as root, pretty much.
- # Once they have finally been eliminated this can all go... --daniel 2011-04-08
- if Puppet.features.posix? then
- def self.in_tmp(path)
- path =~ /^\/tmp/ or path =~ /^\/var\/folders/
- end
- elsif Puppet.features.microsoft_windows?
- def self.in_tmp(path)
- tempdir = File.expand_path(File.join(Dir::LOCAL_APPDATA, "Temp"))
- path =~ /^#{tempdir}/
- end
- else
- fail "Help! Can't find in_tmp for this platform"
- end
-
- def self.cleanup
- $global_tempfiles ||= []
- while path = $global_tempfiles.pop do
- fail "Not deleting tmpfile #{path} outside regular tmpdir" unless in_tmp(path)
-
- begin
- FileUtils.rm_r path, :secure => true
- rescue Errno::ENOENT
- # nothing to do
- end
- end
- end
-
- def tmpfile(name)
- # Generate a temporary file, just for the name...
- source = Tempfile.new(name)
- path = source.path
- source.close!
-
- # ...record it for cleanup,
- $global_tempfiles ||= []
- $global_tempfiles << File.expand_path(path)
-
- # ...and bam.
- path
- end
-
- def tmpdir(name)
- path = tmpfile(name)
- FileUtils.mkdir_p(path)
- path
- end
-end
diff --git a/spec/lib/puppet_spec/fixtures.rb b/spec/lib/puppet_spec/fixtures.rb
deleted file mode 100755
index 7f6bc2a..0000000
--- a/spec/lib/puppet_spec/fixtures.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-module PuppetSpec::Fixtures
- def fixtures(*rest)
- File.join(PuppetSpec::FIXTURE_DIR, *rest)
- end
- def my_fixture_dir
- callers = caller
- while line = callers.shift do
- next unless found = line.match(%r{/spec/(.*)_spec\.rb:})
- return fixtures(found[1])
- end
- fail "sorry, I couldn't work out your path from the caller stack!"
- end
- def my_fixture(name)
- file = File.join(my_fixture_dir, name)
- unless File.readable? file then
- fail Puppet::DevError, "fixture '#{name}' for #{my_fixture_dir} is not readable"
- end
- return file
- end
- def my_fixtures(glob = '*', flags = 0)
- files = Dir.glob(File.join(my_fixture_dir, glob), flags)
- unless files.length > 0 then
- fail Puppet::DevError, "fixture '#{glob}' for #{my_fixture_dir} had no files!"
- end
- block_given? and files.each do |file| yield file end
- files
- end
-end
diff --git a/spec/lib/puppet_spec/matchers.rb b/spec/lib/puppet_spec/matchers.rb
deleted file mode 100644
index 77f5803..0000000
--- a/spec/lib/puppet_spec/matchers.rb
+++ /dev/null
@@ -1,87 +0,0 @@
-require 'stringio'
-
-########################################################################
-# Backward compatibility for Jenkins outdated environment.
-module RSpec
- module Matchers
- module BlockAliases
- alias_method :to, :should unless method_defined? :to
- alias_method :to_not, :should_not unless method_defined? :to_not
- alias_method :not_to, :should_not unless method_defined? :not_to
- end
- end
-end
-
-
-########################################################################
-# Custom matchers...
-RSpec::Matchers.define :have_matching_element do |expected|
- match do |actual|
- actual.any? { |item| item =~ expected }
- end
-end
-
-
-RSpec::Matchers.define :exit_with do |expected|
- actual = nil
- match do |block|
- begin
- block.call
- rescue SystemExit => e
- actual = e.status
- end
- actual and actual == expected
- end
- failure_message_for_should do |block|
- "expected exit with code #{expected} but " +
- (actual.nil? ? " exit was not called" : "we exited with #{actual} instead")
- end
- failure_message_for_should_not do |block|
- "expected that exit would not be called with #{expected}"
- end
- description do
- "expect exit with #{expected}"
- end
-end
-
-
-RSpec::Matchers.define :have_printed do |expected|
- match do |block|
- $stderr = $stdout = StringIO.new
-
- begin
- block.call
- ensure
- $stdout.rewind
- @actual = $stdout.read
-
- $stdout = STDOUT
- $stderr = STDERR
- end
-
- if @actual then
- case expected
- when String
- @actual.include? expected
- when Regexp
- expected.match @actual
- else
- raise ArgumentError, "No idea how to match a #{@actual.class.name}"
- end
- end
- end
-
- failure_message_for_should do |actual|
- if actual.nil? then
- "expected #{expected.inspect}, but nothing was printed"
- else
- "expected #{expected.inspect} to be printed; got:\n#{actual}"
- end
- end
-
- description do
- "expect #{expected.inspect} to be printed"
- end
-
- diffable
-end
diff --git a/spec/lib/puppet_spec/verbose.rb b/spec/lib/puppet_spec/verbose.rb
deleted file mode 100755
index d9834f2..0000000
--- a/spec/lib/puppet_spec/verbose.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-# Support code for running stuff with warnings disabled.
-module Kernel
- def with_verbose_disabled
- verbose, $VERBOSE = $VERBOSE, nil
- result = yield
- $VERBOSE = verbose
- return result
- end
-end
diff --git a/spec/monkey_patches/publicize_methods.rb b/spec/monkey_patches/publicize_methods.rb
index b39e9c0..f3a1abf 100755
--- a/spec/monkey_patches/publicize_methods.rb
+++ b/spec/monkey_patches/publicize_methods.rb
@@ -8,4 +8,3 @@ class Class
self.class_eval { private(*saved_private_instance_methods) }
end
end
-
diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb
index 87aac34..931d35c 100644
--- a/spec/spec_helper.rb
+++ b/spec/spec_helper.rb
@@ -1,8 +1,6 @@
dir = File.expand_path(File.dirname(__FILE__))
$LOAD_PATH.unshift File.join(dir, 'lib')
-p dir
-
# Don't want puppet getting the command line arguments for rake or autotest
ARGV.clear
@@ -12,94 +10,19 @@ 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'
-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
-
- 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
+require 'puppetlabs_spec_helper/module_spec_helper'
RSpec.configure do |config|
- include PuppetSpec::Fixtures
-
- config.mock_with :mocha
-
+ # FIXME REVISIT - We may want to delegate to Facter like we do in
+ # Puppet::PuppetSpecInitializer.initialize_via_testhelper(config) because
+ # this behavior is a duplication of the spec_helper in Facter.
config.before :each do
- GC.disable
-
- # these globals are set by Application
- $puppet_application_mode = nil
- $puppet_application_name = nil
-
- # 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)
-
- # Set the confdir and vardir to gibberish so that tests
- # have to be correctly mocked.
- Puppet[:confdir] = "/dev/null"
- Puppet[:vardir] = "/dev/null"
-
- # Avoid opening ports to the outside world
- Puppet.settings[:bindaddress] = "127.0.0.1"
-
- @logs = []
- Puppet::Util::Log.newdestination(Puppet::Test::LogCollector.new(@logs))
-
- @log_level = Puppet::Util::Log.level
- end
-
- config.after :each do
- Puppet.settings.clear
- 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
+ # Ensure that we don't accidentally cache facts and environment between
+ # test cases. This requires each example group to explicitly load the
+ # facts being exercised with something like
+ # Facter.collection.loader.load(:ipaddress)
+ Facter::Util::Loader.any_instance.stubs(:load_all)
+ Facter.clear
+ Facter.clear_messages
end
end
diff --git a/spec/unit/facter/pe_required_facts_spec.rb b/spec/unit/facter/pe_required_facts_spec.rb
new file mode 100644
index 0000000..f219b37
--- /dev/null
+++ b/spec/unit/facter/pe_required_facts_spec.rb
@@ -0,0 +1,69 @@
+# Puppet Enterprise requires the following facts to be set in order to operate.
+# These facts are set using the file ???? and the two facts are
+# `fact_stomp_port`, and `fact_stomp_server`.
+#
+
+require 'spec_helper'
+
+describe "External facts in /etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt" do
+ context "With Facter 1.6.17 which does not have external facts support" do
+ before :each do
+ Facter.stubs(:version).returns("1.6.17")
+ # Stub out the filesystem for stdlib
+ Dir.stubs(:entries).with("/etc/puppetlabs/facter/facts.d").
+ returns(['puppet_enterprise_installer.txt'])
+ Dir.stubs(:entries).with("/etc/facter/facts.d").returns([])
+ File.stubs(:readlines).with('/etc/puppetlabs/facter/facts.d/puppet_enterprise_installer.txt').
+ returns([
+ "fact_stomp_port=61613\n",
+ "fact_stomp_server=puppetmaster.acme.com\n",
+ "fact_is_puppetagent=true\n",
+ "fact_is_puppetmaster=false\n",
+ "fact_is_puppetca=false\n",
+ "fact_is_puppetconsole=false\n",
+ ])
+ if Facter.collection.respond_to? :load
+ Facter.collection.load(:facter_dot_d)
+ else
+ Facter.collection.loader.load(:facter_dot_d)
+ end
+ end
+
+ it 'defines fact_stomp_port' do
+ Facter.fact(:fact_stomp_port).value.should == '61613'
+ end
+ it 'defines fact_stomp_server' do
+ Facter.fact(:fact_stomp_server).value.should == 'puppetmaster.acme.com'
+ end
+ it 'defines fact_is_puppetagent' do
+ Facter.fact(:fact_is_puppetagent).value.should == 'true'
+ end
+ it 'defines fact_is_puppetmaster' do
+ Facter.fact(:fact_is_puppetmaster).value.should == 'false'
+ end
+ it 'defines fact_is_puppetca' do
+ Facter.fact(:fact_is_puppetca).value.should == 'false'
+ end
+ it 'defines fact_is_puppetconsole' do
+ Facter.fact(:fact_is_puppetconsole).value.should == 'false'
+ end
+ end
+
+ [ '1.7.1', '2.0.1' ].each do |v|
+ context "With Facter #{v} which has external facts support" do
+ before :each do
+ Facter.stubs(:version).returns(v)
+ end
+
+ it 'does not call Facter::Util::DotD.new' do
+ Facter::Util::DotD.expects(:new).never
+
+ if Facter.collection.respond_to? :load
+ Facter.collection.load(:facter_dot_d)
+ else
+ Facter.collection.loader.load(:facter_dot_d)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/facter/pe_version_spec.rb b/spec/unit/facter/pe_version_spec.rb
new file mode 100644
index 0000000..931c6d4
--- /dev/null
+++ b/spec/unit/facter/pe_version_spec.rb
@@ -0,0 +1,76 @@
+#!/usr/bin/env rspec
+
+require 'spec_helper'
+
+describe "PE Version specs" do
+ before :each do
+ # Explicitly load the pe_version.rb file which contains generated facts
+ # that cannot be automatically loaded. Puppet 2.x implements
+ # Facter.collection.load while Facter 1.x markes Facter.collection.load as
+ # a private method.
+ if Facter.collection.respond_to? :load
+ Facter.collection.load(:pe_version)
+ else
+ Facter.collection.loader.load(:pe_version)
+ end
+ end
+
+ context "If PE is installed" do
+ %w{ 2.6.1 2.10.300 }.each do |version|
+ puppetversion = "2.7.19 (Puppet Enterprise #{version})"
+ context "puppetversion => #{puppetversion}" do
+ before :each do
+ Facter.fact(:puppetversion).stubs(:value).returns(puppetversion)
+ end
+
+ (major,minor,patch) = version.split(".")
+
+ it "Should return true" do
+ Facter.fact(:is_pe).value.should == true
+ end
+
+ it "Should have a version of #{version}" do
+ Facter.fact(:pe_version).value.should == version
+ end
+
+ it "Should have a major version of #{major}" do
+ Facter.fact(:pe_major_version).value.should == major
+ end
+
+ it "Should have a minor version of #{minor}" do
+ Facter.fact(:pe_minor_version).value.should == minor
+ end
+
+ it "Should have a patch version of #{patch}" do
+ Facter.fact(:pe_patch_version).value.should == patch
+ end
+ end
+ end
+ end
+
+ context "When PE is not installed" do
+ before :each do
+ Facter.fact(:puppetversion).stubs(:value).returns("2.7.19")
+ end
+
+ it "is_pe is false" do
+ Facter.fact(:is_pe).value.should == false
+ end
+
+ it "pe_version is nil" do
+ Facter.fact(:pe_version).value.should be_nil
+ end
+
+ it "pe_major_version is nil" do
+ Facter.fact(:pe_major_version).value.should be_nil
+ end
+
+ it "pe_minor_version is nil" do
+ Facter.fact(:pe_minor_version).value.should be_nil
+ end
+
+ it "Should have a patch version" do
+ Facter.fact(:pe_patch_version).value.should be_nil
+ end
+ end
+end
diff --git a/spec/unit/facter/root_home_spec.rb b/spec/unit/facter/root_home_spec.rb
index 8946d9d..ce80684 100644
--- a/spec/unit/facter/root_home_spec.rb
+++ b/spec/unit/facter/root_home_spec.rb
@@ -30,13 +30,11 @@ describe Facter::Util::RootHome do
end
end
context "windows" do
- let(:root_ent) { "FIXME TBD on Windows" }
- let(:expected_root_home) { "FIXME TBD on Windows" }
-
- it "should return FIXME TBD on windows" do
- pending "FIXME: TBD on windows"
- Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(root_ent)
- Facter::Util::RootHome.get_root_home.should == expected_root_home
+ before :each do
+ Facter::Util::Resolution.expects(:exec).with("getent passwd root").returns(nil)
+ end
+ it "should be nil on windows" do
+ Facter::Util::RootHome.get_root_home.should be_nil
end
end
end
diff --git a/spec/unit/facter/util/puppet_settings_spec.rb b/spec/unit/facter/util/puppet_settings_spec.rb
new file mode 100644
index 0000000..c3ce6ea
--- /dev/null
+++ b/spec/unit/facter/util/puppet_settings_spec.rb
@@ -0,0 +1,35 @@
+require 'spec_helper'
+require 'facter/util/puppet_settings'
+
+describe Facter::Util::PuppetSettings do
+
+ describe "#with_puppet" do
+ context "Without Puppet loaded" do
+ before(:each) do
+ Module.expects(:const_get).with("Puppet").raises(NameError)
+ end
+
+ it 'should be nil' do
+ subject.with_puppet { Puppet[:vardir] }.should be_nil
+ end
+ it 'should not yield to the block' do
+ Puppet.expects(:[]).never
+ subject.with_puppet { Puppet[:vardir] }.should be_nil
+ end
+ end
+ context "With Puppet loaded" do
+ module Puppet; end
+ let(:vardir) { "/var/lib/puppet" }
+
+ before :each do
+ Puppet.expects(:[]).with(:vardir).returns vardir
+ end
+ it 'should yield to the block' do
+ subject.with_puppet { Puppet[:vardir] }
+ end
+ it 'should return the nodes vardir' do
+ subject.with_puppet { Puppet[:vardir] }.should eq vardir
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/abs_spec.rb b/spec/unit/puppet/parser/functions/abs_spec.rb
index 65ba2e8..c0b4297 100755
--- a/spec/unit/puppet/parser/functions/abs_spec.rb
+++ b/spec/unit/puppet/parser/functions/abs_spec.rb
@@ -1,31 +1,25 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
+
require 'spec_helper'
describe "the abs function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("abs").should == "function_abs"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_abs([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_abs([]) }.should( raise_error(Puppet::ParseError))
end
it "should convert a negative number into a positive" do
- result = @scope.function_abs(["-34"])
+ result = scope.function_abs(["-34"])
result.should(eq(34))
end
it "should do nothing with a positive number" do
- result = @scope.function_abs(["5678"])
+ result = scope.function_abs(["5678"])
result.should(eq(5678))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/any2array_spec.rb b/spec/unit/puppet/parser/functions/any2array_spec.rb
new file mode 100644
index 0000000..b266e84
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/any2array_spec.rb
@@ -0,0 +1,55 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the any2array function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("any2array").should == "function_any2array"
+ end
+
+ it "should return an empty array if there is less than 1 argument" do
+ result = scope.function_any2array([])
+ result.should(eq([]))
+ end
+
+ it "should convert boolean true to [ true ] " do
+ result = scope.function_any2array([true])
+ result.should(eq([true]))
+ end
+
+ it "should convert one object to [object]" do
+ result = scope.function_any2array(['one'])
+ result.should(eq(['one']))
+ end
+
+ it "should convert multiple objects to [objects]" do
+ result = scope.function_any2array(['one', 'two'])
+ result.should(eq(['one', 'two']))
+ end
+
+ it "should return empty array it was called with" do
+ result = scope.function_any2array([[]])
+ result.should(eq([]))
+ end
+
+ it "should return one-member array it was called with" do
+ result = scope.function_any2array([['string']])
+ result.should(eq(['string']))
+ end
+
+ it "should return multi-member array it was called with" do
+ result = scope.function_any2array([['one', 'two']])
+ result.should(eq(['one', 'two']))
+ end
+
+ it "should return members of a hash it was called with" do
+ result = scope.function_any2array([{ 'key' => 'value' }])
+ result.should(eq(['key', 'value']))
+ end
+
+ it "should return an empty array if it was called with an empty hash" do
+ result = scope.function_any2array([{ }])
+ result.should(eq([]))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/base64_spec.rb b/spec/unit/puppet/parser/functions/base64_spec.rb
new file mode 100755
index 0000000..5faa5e6
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/base64_spec.rb
@@ -0,0 +1,34 @@
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
+
+describe "the base64 function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("base64").should == "function_base64"
+ end
+
+ it "should raise a ParseError if there are other than 2 arguments" do
+ expect { scope.function_base64([]) }.to(raise_error(Puppet::ParseError))
+ expect { scope.function_base64(["asdf"]) }.to(raise_error(Puppet::ParseError))
+ expect { scope.function_base64(["asdf","moo","cow"]) }.to(raise_error(Puppet::ParseError))
+ end
+
+ it "should raise a ParseError if argument 1 isn't 'encode' or 'decode'" do
+ expect { scope.function_base64(["bees","astring"]) }.to(raise_error(Puppet::ParseError, /first argument must be one of/))
+ end
+
+ it "should raise a ParseError if argument 2 isn't a string" do
+ expect { scope.function_base64(["encode",["2"]]) }.to(raise_error(Puppet::ParseError, /second argument must be a string/))
+ end
+
+ it "should encode a encoded string" do
+ result = scope.function_base64(["encode",'thestring'])
+ result.should =~ /\AdGhlc3RyaW5n\n\Z/
+ end
+ it "should decode a base64 encoded string" do
+ result = scope.function_base64(["decode",'dGhlc3RyaW5n'])
+ result.should == 'thestring'
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/bool2num_spec.rb b/spec/unit/puppet/parser/functions/bool2num_spec.rb
index d5da18c..518ac85 100755
--- a/spec/unit/puppet/parser/functions/bool2num_spec.rb
+++ b/spec/unit/puppet/parser/functions/bool2num_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the bool2num function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("bool2num").should == "function_bool2num"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_bool2num([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_bool2num([]) }.should( raise_error(Puppet::ParseError))
end
it "should convert true to 1" do
- result = @scope.function_bool2num([true])
+ result = scope.function_bool2num([true])
result.should(eq(1))
end
it "should convert false to 0" do
- result = @scope.function_bool2num([false])
+ result = scope.function_bool2num([false])
result.should(eq(0))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/capitalize_spec.rb b/spec/unit/puppet/parser/functions/capitalize_spec.rb
index 1c45821..69c9758 100755
--- a/spec/unit/puppet/parser/functions/capitalize_spec.rb
+++ b/spec/unit/puppet/parser/functions/capitalize_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the capitalize function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("capitalize").should == "function_capitalize"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_capitalize([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_capitalize([]) }.should( raise_error(Puppet::ParseError))
end
it "should capitalize the beginning of a string" do
- result = @scope.function_capitalize(["abc"])
+ result = scope.function_capitalize(["abc"])
result.should(eq("Abc"))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/chomp_spec.rb b/spec/unit/puppet/parser/functions/chomp_spec.rb
index 0592115..e425365 100755
--- a/spec/unit/puppet/parser/functions/chomp_spec.rb
+++ b/spec/unit/puppet/parser/functions/chomp_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the chomp function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("chomp").should == "function_chomp"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_chomp([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_chomp([]) }.should( raise_error(Puppet::ParseError))
end
it "should chomp the end of a string" do
- result = @scope.function_chomp(["abc\n"])
+ result = scope.function_chomp(["abc\n"])
result.should(eq("abc"))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/chop_spec.rb b/spec/unit/puppet/parser/functions/chop_spec.rb
index 0c456a8..9e466de 100755
--- a/spec/unit/puppet/parser/functions/chop_spec.rb
+++ b/spec/unit/puppet/parser/functions/chop_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the chop function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("chop").should == "function_chop"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_chop([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_chop([]) }.should( raise_error(Puppet::ParseError))
end
it "should chop the end of a string" do
- result = @scope.function_chop(["asdf\n"])
+ result = scope.function_chop(["asdf\n"])
result.should(eq("asdf"))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/concat_spec.rb b/spec/unit/puppet/parser/functions/concat_spec.rb
new file mode 100644
index 0000000..123188b
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/concat_spec.rb
@@ -0,0 +1,15 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the concat function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_concat([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should be able to concat an array" do
+ result = scope.function_concat([['1','2','3'],['4','5','6']])
+ result.should(eq(['1','2','3','4','5','6']))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/count_spec.rb b/spec/unit/puppet/parser/functions/count_spec.rb
new file mode 100644
index 0000000..2453815
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/count_spec.rb
@@ -0,0 +1,31 @@
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
+
+describe "the count function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("count").should == "function_count"
+ end
+
+ it "should raise a ArgumentError if there is more than 2 arguments" do
+ lambda { scope.function_count(['foo', 'bar', 'baz']) }.should( raise_error(ArgumentError))
+ end
+
+ it "should be able to count arrays" do
+ scope.function_count([["1","2","3"]]).should(eq(3))
+ end
+
+ it "should be able to count matching elements in arrays" do
+ scope.function_count([["1", "2", "2"], "2"]).should(eq(2))
+ end
+
+ it "should not count nil or empty strings" do
+ scope.function_count([["foo","bar",nil,""]]).should(eq(2))
+ end
+
+ it 'does not count an undefined hash key or an out of bound array index (which are both :undef)' do
+ expect(scope.function_count([["foo",:undef,:undef]])).to eq(1)
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/delete_at_spec.rb b/spec/unit/puppet/parser/functions/delete_at_spec.rb
index 27db0c8..d8d9618 100755
--- a/spec/unit/puppet/parser/functions/delete_at_spec.rb
+++ b/spec/unit/puppet/parser/functions/delete_at_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the delete_at function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("delete_at").should == "function_delete_at"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_delete_at([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_delete_at([]) }.should( raise_error(Puppet::ParseError))
end
it "should delete an item at specified location from an array" do
- result = @scope.function_delete_at([['a','b','c'],1])
+ result = scope.function_delete_at([['a','b','c'],1])
result.should(eq(['a','c']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/delete_spec.rb b/spec/unit/puppet/parser/functions/delete_spec.rb
index fab3230..2f29c93 100755
--- a/spec/unit/puppet/parser/functions/delete_spec.rb
+++ b/spec/unit/puppet/parser/functions/delete_spec.rb
@@ -1,26 +1,38 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the delete function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("delete").should == "function_delete"
end
- before :each do
- @scope = Puppet::Parser::Scope.new
+ it "should raise a ParseError if there are fewer than 2 arguments" do
+ lambda { scope.function_delete([]) }.should( raise_error(Puppet::ParseError))
end
- it "should exist" do
- Puppet::Parser::Functions.function("delete").should == "function_delete"
+ it "should raise a ParseError if there are greater than 2 arguments" do
+ lambda { scope.function_delete([[], 'foo', 'bar']) }.should( raise_error(Puppet::ParseError))
end
- it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_delete([]) }.should( raise_error(Puppet::ParseError))
+ it "should raise a TypeError if a number is passed as the first argument" do
+ lambda { scope.function_delete([1, 'bar']) }.should( raise_error(TypeError))
end
- it "should delete an item from an array" do
- result = @scope.function_delete([['a','b','c'],'b'])
+ it "should delete all instances of an element from an array" do
+ result = scope.function_delete([['a','b','c','b'],'b'])
result.should(eq(['a','c']))
end
+ it "should delete all instances of a substring from a string" do
+ result = scope.function_delete(['foobarbabarz','bar'])
+ result.should(eq('foobaz'))
+ end
+
+ it "should delete a key from a hash" do
+ result = scope.function_delete([{ 'a' => 1, 'b' => 2, 'c' => 3 },'b'])
+ result.should(eq({ 'a' => 1, 'c' => 3 }))
+ end
+
end
diff --git a/spec/unit/puppet/parser/functions/difference_spec.rb b/spec/unit/puppet/parser/functions/difference_spec.rb
new file mode 100644
index 0000000..9feff09
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/difference_spec.rb
@@ -0,0 +1,19 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the difference function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("difference").should == "function_difference"
+ end
+
+ it "should raise a ParseError if there are fewer than 2 arguments" do
+ lambda { scope.function_difference([]) }.should( raise_error(Puppet::ParseError) )
+ end
+
+ it "should return the difference between two arrays" do
+ result = scope.function_difference([["a","b","c"],["b","c","d"]])
+ result.should(eq(["a"]))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/dirname_spec.rb b/spec/unit/puppet/parser/functions/dirname_spec.rb
new file mode 100755
index 0000000..fb3b4fe
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/dirname_spec.rb
@@ -0,0 +1,24 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the dirname function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("dirname").should == "function_dirname"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_dirname([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should return dirname for an absolute path" do
+ result = scope.function_dirname(['/path/to/a/file.ext'])
+ result.should(eq('/path/to/a'))
+ end
+
+ it "should return dirname for a relative path" do
+ result = scope.function_dirname(['path/to/a/file.ext'])
+ result.should(eq('path/to/a'))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/downcase_spec.rb b/spec/unit/puppet/parser/functions/downcase_spec.rb
index 0bccd5f..acef1f0 100755
--- a/spec/unit/puppet/parser/functions/downcase_spec.rb
+++ b/spec/unit/puppet/parser/functions/downcase_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the downcase function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("downcase").should == "function_downcase"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_downcase([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_downcase([]) }.should( raise_error(Puppet::ParseError))
end
it "should downcase a string" do
- result = @scope.function_downcase(["ASFD"])
+ result = scope.function_downcase(["ASFD"])
result.should(eq("asfd"))
end
it "should do nothing to a string that is already downcase" do
- result = @scope.function_downcase(["asdf asdf"])
+ result = scope.function_downcase(["asdf asdf"])
result.should(eq("asdf asdf"))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/empty_spec.rb b/spec/unit/puppet/parser/functions/empty_spec.rb
index cb0021f..7745875 100755
--- a/spec/unit/puppet/parser/functions/empty_spec.rb
+++ b/spec/unit/puppet/parser/functions/empty_spec.rb
@@ -1,31 +1,23 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the empty function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
-
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("empty").should == "function_empty"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_empty([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_empty([]) }.should( raise_error(Puppet::ParseError))
end
it "should return a true for an empty string" do
- result = @scope.function_empty([''])
+ result = scope.function_empty([''])
result.should(eq(true))
end
it "should return a false for a non-empty string" do
- result = @scope.function_empty(['asdf'])
+ result = scope.function_empty(['asdf'])
result.should(eq(false))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/flatten_spec.rb b/spec/unit/puppet/parser/functions/flatten_spec.rb
index 7bedeb2..dba7a6b 100755
--- a/spec/unit/puppet/parser/functions/flatten_spec.rb
+++ b/spec/unit/puppet/parser/functions/flatten_spec.rb
@@ -1,31 +1,27 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the flatten function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
-
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("flatten").should == "function_flatten"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_flatten([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_flatten([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should raise a ParseError if there is more than 1 argument" do
+ lambda { scope.function_flatten([[], []]) }.should( raise_error(Puppet::ParseError))
end
it "should flatten a complex data structure" do
- result = @scope.function_flatten([["a","b",["c",["d","e"],"f","g"]]])
+ result = scope.function_flatten([["a","b",["c",["d","e"],"f","g"]]])
result.should(eq(["a","b","c","d","e","f","g"]))
end
it "should do nothing to a structure that is already flat" do
- result = @scope.function_flatten([["a","b","c","d"]])
+ result = scope.function_flatten([["a","b","c","d"]])
result.should(eq(["a","b","c","d"]))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/floor_spec.rb b/spec/unit/puppet/parser/functions/floor_spec.rb
new file mode 100644
index 0000000..dbc8c77
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/floor_spec.rb
@@ -0,0 +1,39 @@
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
+
+describe "the floor function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("floor").should == "function_floor"
+ end
+
+ it "should raise a ParseError if there is less than 1 argument" do
+ lambda { scope.function_floor([]) }.should( raise_error(Puppet::ParseError, /Wrong number of arguments/))
+ end
+
+ it "should should raise a ParseError if input isn't numeric (eg. String)" do
+ lambda { scope.function_floor(["foo"]) }.should( raise_error(Puppet::ParseError, /Wrong argument type/))
+ end
+
+ it "should should raise a ParseError if input isn't numeric (eg. Boolean)" do
+ lambda { scope.function_floor([true]) }.should( raise_error(Puppet::ParseError, /Wrong argument type/))
+ end
+
+ it "should return an integer when a numeric type is passed" do
+ result = scope.function_floor([12.4])
+ result.is_a?(Integer).should(eq(true))
+ end
+
+ it "should return the input when an integer is passed" do
+ result = scope.function_floor([7])
+ result.should(eq(7))
+ end
+
+ it "should return the largest integer less than or equal to the input" do
+ result = scope.function_floor([3.8])
+ result.should(eq(3))
+ 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..2577723
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/fqdn_rotate_spec.rb
@@ -0,0 +1,33 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the fqdn_rotate function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ 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
diff --git a/spec/unit/puppet/parser/functions/get_module_path_spec.rb b/spec/unit/puppet/parser/functions/get_module_path_spec.rb
new file mode 100644
index 0000000..486bef6
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/get_module_path_spec.rb
@@ -0,0 +1,46 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:get_module_path) do
+ Internals = PuppetlabsSpec::PuppetInternals
+ class StubModule
+ attr_reader :path
+ def initialize(path)
+ @path = path
+ end
+ end
+
+ def scope(environment = "production")
+ Internals.scope(:compiler => Internals.compiler(:node => Internals.node(:environment => environment)))
+ end
+
+ it 'should only allow one argument' do
+ expect { scope.function_get_module_path([]) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
+ expect { scope.function_get_module_path(['1','2','3']) }.to raise_error(Puppet::ParseError, /Wrong number of arguments, expects one/)
+ end
+ it 'should raise an exception when the module cannot be found' do
+ expect { scope.function_get_module_path(['foo']) }.to raise_error(Puppet::ParseError, /Could not find module/)
+ end
+ describe 'when locating a module' do
+ let(:modulepath) { "/tmp/does_not_exist" }
+ let(:path_of_module_foo) { StubModule.new("/tmp/does_not_exist/foo") }
+
+ before(:each) { Puppet[:modulepath] = modulepath }
+
+ it 'should be able to find module paths from the modulepath setting' do
+ Puppet::Module.expects(:find).with('foo', 'production').returns(path_of_module_foo)
+ scope.function_get_module_path(['foo']).should == path_of_module_foo.path
+ end
+ it 'should be able to find module paths when the modulepath is a list' do
+ Puppet[:modulepath] = modulepath + ":/tmp"
+ Puppet::Module.expects(:find).with('foo', 'production').returns(path_of_module_foo)
+ scope.function_get_module_path(['foo']).should == path_of_module_foo.path
+ end
+ it 'should respect the environment' do
+ pending("Disabled on Puppet 2.6.x") if Puppet.version =~ /^2\.6\b/
+ Puppet.settings[:environment] = 'danstestenv'
+ Puppet::Module.expects(:find).with('foo', 'danstestenv').returns(path_of_module_foo)
+ scope('danstestenv').function_get_module_path(['foo']).should == path_of_module_foo.path
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/getvar_spec.rb b/spec/unit/puppet/parser/functions/getvar_spec.rb
index 16edd98..5ff834e 100644
--- a/spec/unit/puppet/parser/functions/getvar_spec.rb
+++ b/spec/unit/puppet/parser/functions/getvar_spec.rb
@@ -1,40 +1,28 @@
-require 'puppet'
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
-# We don't need this for the basic tests we're doing
-# require 'spec_helper'
-
-# Dan mentioned that Nick recommended the function method call
-# to return the string value for the test description.
-# this will not even try the test if the function cannot be
-# loaded.
describe Puppet::Parser::Functions.function(:getvar) do
-
- # Pulled from Dan's create_resources function
- def get_scope
- @topscope = Puppet::Parser::Scope.new
- # This is necessary so we don't try to use the compiler to discover our parent.
- @topscope.parent = nil
- @scope = Puppet::Parser::Scope.new
- @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
- @scope.parent = @topscope
- @compiler = @scope.compiler
- end
-
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
describe 'when calling getvar from puppet' do
it "should not compile when no arguments are passed" do
- Puppet[:code] = 'getvar()'
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
+ Puppet[:code] = '$foo = getvar()'
+ expect {
+ scope.compiler.compile
+ }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
end
+
it "should not compile when too many arguments are passed" do
- Puppet[:code] = 'getvar("foo::bar", "baz")'
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
+ Puppet[:code] = '$foo = getvar("foo::bar", "baz")'
+ expect {
+ scope.compiler.compile
+ }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
end
it "should lookup variables in other namespaces" do
- pending "Puppet doesn't appear to think getvar is an rvalue function... BUG?"
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
Puppet[:code] = <<-'ENDofPUPPETcode'
class site::data { $foo = 'baz' }
include site::data
@@ -43,11 +31,7 @@ describe Puppet::Parser::Functions.function(:getvar) do
fail('getvar did not return what we expect')
}
ENDofPUPPETcode
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
-
end
-
end
-
diff --git a/spec/unit/puppet/parser/functions/grep_spec.rb b/spec/unit/puppet/parser/functions/grep_spec.rb
index b1f647c..a93b842 100755
--- a/spec/unit/puppet/parser/functions/grep_spec.rb
+++ b/spec/unit/puppet/parser/functions/grep_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the grep function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("grep").should == "function_grep"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_grep([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_grep([]) }.should( raise_error(Puppet::ParseError))
end
it "should grep contents from an array" do
- result = @scope.function_grep([["aaabbb","bbbccc","dddeee"], "bbb"])
+ result = scope.function_grep([["aaabbb","bbbccc","dddeee"], "bbb"])
result.should(eq(["aaabbb","bbbccc"]))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/has_interface_with_spec.rb b/spec/unit/puppet/parser/functions/has_interface_with_spec.rb
new file mode 100755
index 0000000..c5264e4
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/has_interface_with_spec.rb
@@ -0,0 +1,64 @@
+#!/usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:has_interface_with) do
+
+ let(:scope) do
+ PuppetlabsSpec::PuppetInternals.scope
+ end
+
+ # The subject of these examples is the method itself.
+ subject do
+ function_name = Puppet::Parser::Functions.function(:has_interface_with)
+ scope.method(function_name)
+ end
+
+ # We need to mock out the Facts so we can specify how we expect this function
+ # to behave on different platforms.
+ context "On Mac OS X Systems" do
+ before :each do
+ scope.stubs(:lookupvar).with("interfaces").returns('lo0,gif0,stf0,en1,p2p0,fw0,en0,vmnet1,vmnet8,utun0')
+ end
+ it 'should have loopback (lo0)' do
+ subject.call(['lo0']).should be_true
+ end
+ it 'should not have loopback (lo)' do
+ subject.call(['lo']).should be_false
+ end
+ end
+ context "On Linux Systems" do
+ before :each do
+ scope.stubs(:lookupvar).with("interfaces").returns('eth0,lo')
+ scope.stubs(:lookupvar).with("ipaddress").returns('10.0.0.1')
+ scope.stubs(:lookupvar).with("ipaddress_lo").returns('127.0.0.1')
+ scope.stubs(:lookupvar).with("ipaddress_eth0").returns('10.0.0.1')
+ scope.stubs(:lookupvar).with('muppet').returns('kermit')
+ scope.stubs(:lookupvar).with('muppet_lo').returns('mspiggy')
+ scope.stubs(:lookupvar).with('muppet_eth0').returns('kermit')
+ end
+ it 'should have loopback (lo)' do
+ subject.call(['lo']).should be_true
+ end
+ it 'should not have loopback (lo0)' do
+ subject.call(['lo0']).should be_false
+ end
+ it 'should have ipaddress with 127.0.0.1' do
+ subject.call(['ipaddress', '127.0.0.1']).should be_true
+ end
+ it 'should have ipaddress with 10.0.0.1' do
+ subject.call(['ipaddress', '10.0.0.1']).should be_true
+ end
+ it 'should not have ipaddress with 10.0.0.2' do
+ subject.call(['ipaddress', '10.0.0.2']).should be_false
+ end
+ it 'should have muppet named kermit' do
+ subject.call(['muppet', 'kermit']).should be_true
+ end
+ it 'should have muppet named mspiggy' do
+ subject.call(['muppet', 'mspiggy']).should be_true
+ end
+ it 'should not have muppet named bigbird' do
+ subject.call(['muppet', 'bigbird']).should be_false
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/has_ip_address_spec.rb b/spec/unit/puppet/parser/functions/has_ip_address_spec.rb
new file mode 100755
index 0000000..5a68460
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/has_ip_address_spec.rb
@@ -0,0 +1,39 @@
+#!/usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:has_ip_address) do
+
+ let(:scope) do
+ PuppetlabsSpec::PuppetInternals.scope
+ end
+
+ subject do
+ function_name = Puppet::Parser::Functions.function(:has_ip_address)
+ scope.method(function_name)
+ end
+
+ context "On Linux Systems" do
+ before :each do
+ scope.stubs(:lookupvar).with('interfaces').returns('eth0,lo')
+ scope.stubs(:lookupvar).with('ipaddress').returns('10.0.2.15')
+ scope.stubs(:lookupvar).with('ipaddress_eth0').returns('10.0.2.15')
+ scope.stubs(:lookupvar).with('ipaddress_lo').returns('127.0.0.1')
+ end
+
+ it 'should have primary address (10.0.2.15)' do
+ subject.call(['10.0.2.15']).should be_true
+ end
+
+ it 'should have lookupback address (127.0.0.1)' do
+ subject.call(['127.0.0.1']).should be_true
+ end
+
+ it 'should not have other address' do
+ subject.call(['192.1681.1.1']).should be_false
+ end
+
+ it 'should not have "mspiggy" on an interface' do
+ subject.call(['mspiggy']).should be_false
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/has_ip_network_spec.rb b/spec/unit/puppet/parser/functions/has_ip_network_spec.rb
new file mode 100755
index 0000000..c3a289e
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/has_ip_network_spec.rb
@@ -0,0 +1,36 @@
+#!/usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:has_ip_network) do
+
+ let(:scope) do
+ PuppetlabsSpec::PuppetInternals.scope
+ end
+
+ subject do
+ function_name = Puppet::Parser::Functions.function(:has_ip_network)
+ scope.method(function_name)
+ end
+
+ context "On Linux Systems" do
+ before :each do
+ scope.stubs(:lookupvar).with('interfaces').returns('eth0,lo')
+ scope.stubs(:lookupvar).with('network').returns(:undefined)
+ scope.stubs(:lookupvar).with('network_eth0').returns('10.0.2.0')
+ scope.stubs(:lookupvar).with('network_lo').returns('127.0.0.1')
+ end
+
+ it 'should have primary network (10.0.2.0)' do
+ subject.call(['10.0.2.0']).should be_true
+ end
+
+ it 'should have loopback network (127.0.0.0)' do
+ subject.call(['127.0.0.1']).should be_true
+ end
+
+ it 'should not have other network' do
+ subject.call(['192.168.1.0']).should be_false
+ end
+ end
+end
+
diff --git a/spec/unit/puppet/parser/functions/has_key_spec.rb b/spec/unit/puppet/parser/functions/has_key_spec.rb
index d1dcd15..490daea 100644
--- a/spec/unit/puppet/parser/functions/has_key_spec.rb
+++ b/spec/unit/puppet/parser/functions/has_key_spec.rb
@@ -1,46 +1,42 @@
-require 'puppet'
-require 'mocha'
-describe Puppet::Parser::Functions.function(:has_key) do
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
- # Pulled from Dan's create_resources function
- # TODO - this should be moved to spec_helper since the
- # logic is likely to be applied to multiple rspec files.
- let(:compiler) {
- topscope = Puppet::Parser::Scope.new
- # This is necessary so we don't try to use the compiler to discover our parent.
- topscope.parent = nil
- my_scope = Puppet::Parser::Scope.new
- my_scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
- my_scope.parent = topscope
- compiler = my_scope.compiler
- }
- let(:scope) {
- scope = Puppet::Parser::Scope.new
- scope.stubs(:environment).returns(Puppet::Node::Environment.new('production'))
- scope
- }
+describe Puppet::Parser::Functions.function(:has_key) do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
describe 'when calling has_key from puppet' do
it "should not compile when no arguments are passed" do
- Puppet[:code] = 'has_key()'
- expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
+ Puppet[:code] = '$x = has_key()'
+ expect {
+ scope.compiler.compile
+ }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
end
+
it "should not compile when 1 argument is passed" do
- Puppet[:code] = "has_key('foo')"
- expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
+ Puppet[:code] = "$x = has_key('foo')"
+ expect {
+ scope.compiler.compile
+ }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
end
+
it "should require the first value to be a Hash" do
- Puppet[:code] = "has_key('foo', 'bar')"
- expect { compiler.compile }.should raise_error(Puppet::ParseError, /expects the first argument to be a hash/)
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
+ Puppet[:code] = "$x = has_key('foo', 'bar')"
+ expect {
+ scope.compiler.compile
+ }.to raise_error(Puppet::ParseError, /expects the first argument to be a hash/)
end
end
+
describe 'when calling the function has_key from a scope instance' do
it 'should detect existing keys' do
scope.function_has_key([{'one' => 1}, 'one']).should be_true
end
+
it 'should detect existing keys' do
scope.function_has_key([{'one' => 1}, 'two']).should be_false
end
end
-
end
diff --git a/spec/unit/puppet/parser/functions/hash_spec.rb b/spec/unit/puppet/parser/functions/hash_spec.rb
index 6d3d48c..7c91be9 100644
--- a/spec/unit/puppet/parser/functions/hash_spec.rb
+++ b/spec/unit/puppet/parser/functions/hash_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the hash function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("hash").should == "function_hash"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_hash([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_hash([]) }.should( raise_error(Puppet::ParseError))
end
it "should convert an array to a hash" do
- result = @scope.function_hash([['a',1,'b',2,'c',3]])
+ result = scope.function_hash([['a',1,'b',2,'c',3]])
result.should(eq({'a'=>1,'b'=>2,'c'=>3}))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/intersection_spec.rb b/spec/unit/puppet/parser/functions/intersection_spec.rb
new file mode 100644
index 0000000..fd44f7f
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/intersection_spec.rb
@@ -0,0 +1,19 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the intersection function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("intersection").should == "function_intersection"
+ end
+
+ it "should raise a ParseError if there are fewer than 2 arguments" do
+ lambda { scope.function_intersection([]) }.should( raise_error(Puppet::ParseError) )
+ end
+
+ it "should return the intersection of two arrays" do
+ result = scope.function_intersection([["a","b","c"],["b","c","d"]])
+ result.should(eq(["b","c"]))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/is_array_spec.rb b/spec/unit/puppet/parser/functions/is_array_spec.rb
index 537595c..e7f4bcd 100644
--- a/spec/unit/puppet/parser/functions/is_array_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_array_spec.rb
@@ -1,36 +1,29 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_array function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_array").should == "function_is_array"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_array([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_array([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if passed an array" do
- result = @scope.function_is_array([[1,2,3]])
+ result = scope.function_is_array([[1,2,3]])
result.should(eq(true))
end
it "should return false if passed a hash" do
- result = @scope.function_is_array([{'a'=>1}])
+ result = scope.function_is_array([{'a'=>1}])
result.should(eq(false))
end
it "should return false if passed a string" do
- result = @scope.function_is_array(["asdf"])
+ result = scope.function_is_array(["asdf"])
result.should(eq(false))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/is_domain_name_spec.rb b/spec/unit/puppet/parser/functions/is_domain_name_spec.rb
index ec7c7f5..f2ea76d 100644
--- a/spec/unit/puppet/parser/functions/is_domain_name_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_domain_name_spec.rb
@@ -1,56 +1,64 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_domain_name function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_domain_name").should == "function_is_domain_name"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_domain_name([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_domain_name([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should return true if a valid short domain name" do
+ result = scope.function_is_domain_name(["x.com"])
+ result.should(be_true)
+ end
+
+ it "should return true if the domain is ." do
+ result = scope.function_is_domain_name(["."])
+ result.should(be_true)
+ end
+
+ it "should return true if the domain is x.com." do
+ result = scope.function_is_domain_name(["x.com."])
+ result.should(be_true)
end
it "should return true if a valid domain name" do
- result = @scope.function_is_domain_name(["foo.bar.com"])
+ result = scope.function_is_domain_name(["foo.bar.com"])
result.should(be_true)
end
it "should allow domain parts to start with numbers" do
- result = @scope.function_is_domain_name(["3foo.2bar.com"])
+ result = scope.function_is_domain_name(["3foo.2bar.com"])
result.should(be_true)
end
it "should allow domain to end with a dot" do
- result = @scope.function_is_domain_name(["3foo.2bar.com."])
+ result = scope.function_is_domain_name(["3foo.2bar.com."])
result.should(be_true)
end
it "should allow a single part domain" do
- result = @scope.function_is_domain_name(["orange"])
+ result = scope.function_is_domain_name(["orange"])
result.should(be_true)
end
it "should return false if domain parts start with hyphens" do
- result = @scope.function_is_domain_name(["-3foo.2bar.com"])
+ result = scope.function_is_domain_name(["-3foo.2bar.com"])
result.should(be_false)
end
it "should return true if domain contains hyphens" do
- result = @scope.function_is_domain_name(["3foo-bar.2bar-fuzz.com"])
+ result = scope.function_is_domain_name(["3foo-bar.2bar-fuzz.com"])
result.should(be_true)
end
it "should return false if domain name contains spaces" do
- result = @scope.function_is_domain_name(["not valid"])
+ result = scope.function_is_domain_name(["not valid"])
result.should(be_false)
end
-
end
diff --git a/spec/unit/puppet/parser/functions/is_float_spec.rb b/spec/unit/puppet/parser/functions/is_float_spec.rb
index 55ba8cf..b7d73b0 100644
--- a/spec/unit/puppet/parser/functions/is_float_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_float_spec.rb
@@ -1,36 +1,33 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_float function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_float").should == "function_is_float"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_float([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_float([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if a float" do
- result = @scope.function_is_float(["0.12"])
+ result = scope.function_is_float(["0.12"])
result.should(eq(true))
end
it "should return false if a string" do
- result = @scope.function_is_float(["asdf"])
+ result = scope.function_is_float(["asdf"])
result.should(eq(false))
end
it "should return false if an integer" do
- result = @scope.function_is_float(["3"])
+ result = scope.function_is_float(["3"])
result.should(eq(false))
end
-
+ it "should return true if a float is created from an arithmetical operation" do
+ result = scope.function_is_float([3.2*2])
+ result.should(eq(true))
+ end
end
diff --git a/spec/unit/puppet/parser/functions/is_function_available.rb b/spec/unit/puppet/parser/functions/is_function_available.rb
new file mode 100644
index 0000000..bd40c51
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/is_function_available.rb
@@ -0,0 +1,31 @@
+#!/usr/bin/env rspec
+require 'spec_helper'
+
+describe "the is_function_available 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("is_function_available").should == "function_is_function_available"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { @scope.function_is_function_available([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should return false if a nonexistent function is passed" do
+ result = @scope.function_is_function_available(['jeff_mccunes_left_sock'])
+ result.should(eq(false))
+ end
+
+ it "should return true if an available function is passed" do
+ result = @scope.function_is_function_available(['require'])
+ result.should(eq(true))
+ end
+
+end
diff --git a/spec/unit/puppet/parser/functions/is_hash_spec.rb b/spec/unit/puppet/parser/functions/is_hash_spec.rb
index 94364f5..bbebf39 100644
--- a/spec/unit/puppet/parser/functions/is_hash_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_hash_spec.rb
@@ -1,36 +1,29 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_hash function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_hash").should == "function_is_hash"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_hash([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_hash([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if passed a hash" do
- result = @scope.function_is_hash([{"a"=>1,"b"=>2}])
+ result = scope.function_is_hash([{"a"=>1,"b"=>2}])
result.should(eq(true))
end
it "should return false if passed an array" do
- result = @scope.function_is_hash([["a","b"]])
+ result = scope.function_is_hash([["a","b"]])
result.should(eq(false))
end
it "should return false if passed a string" do
- result = @scope.function_is_hash(["asdf"])
+ result = scope.function_is_hash(["asdf"])
result.should(eq(false))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/is_integer_spec.rb b/spec/unit/puppet/parser/functions/is_integer_spec.rb
index faf6f2d..4335795 100644
--- a/spec/unit/puppet/parser/functions/is_integer_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_integer_spec.rb
@@ -1,36 +1,34 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_integer function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_integer").should == "function_is_integer"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_integer([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_integer([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if an integer" do
- result = @scope.function_is_integer(["3"])
+ result = scope.function_is_integer(["3"])
result.should(eq(true))
end
it "should return false if a float" do
- result = @scope.function_is_integer(["3.2"])
+ result = scope.function_is_integer(["3.2"])
result.should(eq(false))
end
it "should return false if a string" do
- result = @scope.function_is_integer(["asdf"])
+ result = scope.function_is_integer(["asdf"])
result.should(eq(false))
end
+ it "should return true if an integer is created from an arithmetical operation" do
+ result = scope.function_is_integer([3*2])
+ result.should(eq(true))
+ end
end
diff --git a/spec/unit/puppet/parser/functions/is_ip_address_spec.rb b/spec/unit/puppet/parser/functions/is_ip_address_spec.rb
index 98ce828..c0debb3 100644
--- a/spec/unit/puppet/parser/functions/is_ip_address_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_ip_address_spec.rb
@@ -1,45 +1,39 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_ip_address function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_ip_address").should == "function_is_ip_address"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_ip_address([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_ip_address([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if an IPv4 address" do
- result = @scope.function_is_ip_address(["1.2.3.4"])
+ result = scope.function_is_ip_address(["1.2.3.4"])
result.should(eq(true))
end
it "should return true if a full IPv6 address" do
- result = @scope.function_is_ip_address(["fe80:0000:cd12:d123:e2f8:47ff:fe09:dd74"])
+ result = scope.function_is_ip_address(["fe80:0000:cd12:d123:e2f8:47ff:fe09:dd74"])
result.should(eq(true))
end
it "should return true if a compressed IPv6 address" do
- result = @scope.function_is_ip_address(["fe00::1"])
+ result = scope.function_is_ip_address(["fe00::1"])
result.should(eq(true))
end
it "should return false if not valid" do
- result = @scope.function_is_ip_address(["asdf"])
+ result = scope.function_is_ip_address(["asdf"])
result.should(eq(false))
end
it "should return false if IP octets out of range" do
- result = @scope.function_is_ip_address(["1.1.1.300"])
+ result = scope.function_is_ip_address(["1.1.1.300"])
result.should(eq(false))
end
end
diff --git a/spec/unit/puppet/parser/functions/is_mac_address_spec.rb b/spec/unit/puppet/parser/functions/is_mac_address_spec.rb
index c9b9637..ca9c590 100644
--- a/spec/unit/puppet/parser/functions/is_mac_address_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_mac_address_spec.rb
@@ -1,36 +1,29 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_mac_address function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_mac_address").should == "function_is_mac_address"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_mac_address([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_mac_address([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if a valid mac address" do
- result = @scope.function_is_mac_address(["00:a0:1f:12:7f:a0"])
+ result = scope.function_is_mac_address(["00:a0:1f:12:7f:a0"])
result.should(eq(true))
end
it "should return false if octets are out of range" do
- result = @scope.function_is_mac_address(["00:a0:1f:12:7f:g0"])
+ result = scope.function_is_mac_address(["00:a0:1f:12:7f:g0"])
result.should(eq(false))
end
it "should return false if not valid" do
- result = @scope.function_is_mac_address(["not valid"])
+ result = scope.function_is_mac_address(["not valid"])
result.should(eq(false))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/is_numeric_spec.rb b/spec/unit/puppet/parser/functions/is_numeric_spec.rb
index 2191b7b..d7440fb 100644
--- a/spec/unit/puppet/parser/functions/is_numeric_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_numeric_spec.rb
@@ -1,36 +1,39 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_numeric function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_numeric").should == "function_is_numeric"
end
it "should raise a ParseError if there is less than 1 argument" do
- lambda { @scope.function_is_numeric([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_numeric([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if an integer" do
- result = @scope.function_is_numeric(["3"])
+ result = scope.function_is_numeric(["3"])
result.should(eq(true))
end
it "should return true if a float" do
- result = @scope.function_is_numeric(["3.2"])
+ result = scope.function_is_numeric(["3.2"])
+ result.should(eq(true))
+ end
+
+ it "should return true if an integer is created from an arithmetical operation" do
+ result = scope.function_is_numeric([3*2])
+ result.should(eq(true))
+ end
+
+ it "should return true if a float is created from an arithmetical operation" do
+ result = scope.function_is_numeric([3.2*2])
result.should(eq(true))
end
it "should return false if a string" do
- result = @scope.function_is_numeric(["asdf"])
+ result = scope.function_is_numeric(["asdf"])
result.should(eq(false))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/is_string_spec.rb b/spec/unit/puppet/parser/functions/is_string_spec.rb
index 4f3f5fd..3756bea 100644
--- a/spec/unit/puppet/parser/functions/is_string_spec.rb
+++ b/spec/unit/puppet/parser/functions/is_string_spec.rb
@@ -1,41 +1,34 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the is_string function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("is_string").should == "function_is_string"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_is_string([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_is_string([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if a string" do
- result = @scope.function_is_string(["asdf"])
+ result = scope.function_is_string(["asdf"])
result.should(eq(true))
end
it "should return false if an integer" do
- result = @scope.function_is_string(["3"])
+ result = scope.function_is_string(["3"])
result.should(eq(false))
end
it "should return false if a float" do
- result = @scope.function_is_string(["3.23"])
+ result = scope.function_is_string(["3.23"])
result.should(eq(false))
end
it "should return false if an array" do
- result = @scope.function_is_string([["a","b","c"]])
+ result = scope.function_is_string([["a","b","c"]])
result.should(eq(false))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/join_keys_to_values_spec.rb b/spec/unit/puppet/parser/functions/join_keys_to_values_spec.rb
new file mode 100644
index 0000000..a52fb71
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/join_keys_to_values_spec.rb
@@ -0,0 +1,40 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the join_keys_to_values function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("join_keys_to_values").should == "function_join_keys_to_values"
+ end
+
+ it "should raise a ParseError if there are fewer than two arguments" do
+ lambda { scope.function_join_keys_to_values([{}]) }.should raise_error Puppet::ParseError
+ end
+
+ it "should raise a ParseError if there are greater than two arguments" do
+ lambda { scope.function_join_keys_to_values([{}, 'foo', 'bar']) }.should raise_error Puppet::ParseError
+ end
+
+ it "should raise a TypeError if the first argument is an array" do
+ lambda { scope.function_join_keys_to_values([[1,2], ',']) }.should raise_error TypeError
+ end
+
+ it "should raise a TypeError if the second argument is an array" do
+ lambda { scope.function_join_keys_to_values([{}, [1,2]]) }.should raise_error TypeError
+ end
+
+ it "should raise a TypeError if the second argument is a number" do
+ lambda { scope.function_join_keys_to_values([{}, 1]) }.should raise_error TypeError
+ end
+
+ it "should return an empty array given an empty hash" do
+ result = scope.function_join_keys_to_values([{}, ":"])
+ result.should == []
+ end
+
+ it "should join hash's keys to its values" do
+ result = scope.function_join_keys_to_values([{'a'=>1,2=>'foo',:b=>nil}, ":"])
+ result.should =~ ['a:1','2:foo','b:']
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/join_spec.rb b/spec/unit/puppet/parser/functions/join_spec.rb
index 1b3dec8..aafa1a7 100644
--- a/spec/unit/puppet/parser/functions/join_spec.rb
+++ b/spec/unit/puppet/parser/functions/join_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the join function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("join").should == "function_join"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_join([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_join([]) }.should( raise_error(Puppet::ParseError))
end
it "should join an array into a string" do
- result = @scope.function_join([["a","b","c"], ":"])
+ result = scope.function_join([["a","b","c"], ":"])
result.should(eq("a:b:c"))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/keys_spec.rb b/spec/unit/puppet/parser/functions/keys_spec.rb
index 927be96..fdd7a70 100644
--- a/spec/unit/puppet/parser/functions/keys_spec.rb
+++ b/spec/unit/puppet/parser/functions/keys_spec.rb
@@ -1,26 +1,21 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the keys function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("keys").should == "function_keys"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_keys([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_keys([]) }.should( raise_error(Puppet::ParseError))
end
it "should return an array of keys when given a hash" do
- result = @scope.function_keys([{'a'=>1, 'b' => 2}])
- result.should(eq(['a','b']))
+ result = scope.function_keys([{'a'=>1, 'b'=>2}])
+ # =~ performs 'array with same elements' (set) matching
+ # For more info see RSpec::Matchers::MatchArray
+ result.should =~ ['a','b']
end
-
end
diff --git a/spec/unit/puppet/parser/functions/lstrip_spec.rb b/spec/unit/puppet/parser/functions/lstrip_spec.rb
index ac331fa..b280ae7 100644
--- a/spec/unit/puppet/parser/functions/lstrip_spec.rb
+++ b/spec/unit/puppet/parser/functions/lstrip_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the lstrip function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("lstrip").should == "function_lstrip"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_lstrip([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_lstrip([]) }.should( raise_error(Puppet::ParseError))
end
it "should lstrip a string" do
- result = @scope.function_lstrip([" asdf"])
+ result = scope.function_lstrip([" asdf"])
result.should(eq('asdf'))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/max_spec.rb b/spec/unit/puppet/parser/functions/max_spec.rb
new file mode 100755
index 0000000..ff6f2b3
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/max_spec.rb
@@ -0,0 +1,27 @@
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
+
+describe "the max function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("max").should == "function_max"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_max([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should be able to compare strings" do
+ scope.function_max(["albatross","dog","horse"]).should(eq("horse"))
+ end
+
+ it "should be able to compare numbers" do
+ scope.function_max([6,8,4]).should(eq(8))
+ end
+
+ it "should be able to compare a number with a stringified number" do
+ scope.function_max([1,"2"]).should(eq("2"))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/member_spec.rb b/spec/unit/puppet/parser/functions/member_spec.rb
index 2cebc0d..6e9a023 100644
--- a/spec/unit/puppet/parser/functions/member_spec.rb
+++ b/spec/unit/puppet/parser/functions/member_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the member function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("member").should == "function_member"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_member([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_member([]) }.should( raise_error(Puppet::ParseError))
end
it "should return true if a member is in an array" do
- result = @scope.function_member([["a","b","c"], "a"])
+ result = scope.function_member([["a","b","c"], "a"])
result.should(eq(true))
- end
+ end
it "should return false if a member is not in an array" do
- result = @scope.function_member([["a","b","c"], "d"])
+ result = scope.function_member([["a","b","c"], "d"])
result.should(eq(false))
- end
-
+ end
end
diff --git a/spec/unit/puppet/parser/functions/merge_spec.rb b/spec/unit/puppet/parser/functions/merge_spec.rb
index 71e1869..8a170bb 100644
--- a/spec/unit/puppet/parser/functions/merge_spec.rb
+++ b/spec/unit/puppet/parser/functions/merge_spec.rb
@@ -1,54 +1,52 @@
-require 'puppet'
-require 'mocha'
-describe Puppet::Parser::Functions.function(:merge) do
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
- # Pulled from Dan's create_resources function
- # TODO - these let statements should be moved somewhere
- # where they can be resued
- let(:compiler) {
- topscope = Puppet::Parser::Scope.new
- # This is necessary so we don't try to use the compiler to discover our parent.
- topscope.parent = nil
- my_scope = Puppet::Parser::Scope.new
- my_scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
- my_scope.parent = topscope
- compiler = my_scope.compiler
- }
- let(:scope) {
- scope = Puppet::Parser::Scope.new
- scope.stubs(:environment).returns(Puppet::Node::Environment.new('production'))
- scope
- }
+describe Puppet::Parser::Functions.function(:merge) do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
describe 'when calling merge from puppet' do
it "should not compile when no arguments are passed" do
- Puppet[:code] = 'merge()'
- expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
+ Puppet[:code] = '$x = merge()'
+ expect {
+ scope.compiler.compile
+ }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
end
+
it "should not compile when 1 argument is passed" do
- Puppet[:code] = "$my_hash={'one' => 1}\nmerge($my_hash)"
- expect { compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+ pending("Fails on 2.6.x, see bug #15912") if Puppet.version =~ /^2\.6\./
+ Puppet[:code] = "$my_hash={'one' => 1}\n$x = merge($my_hash)"
+ expect {
+ scope.compiler.compile
+ }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
end
end
+
describe 'when calling merge on the scope instance' do
it 'should require all parameters are hashes' do
- expect { new_hash = scope.function_merge([{}, '2'])}.should raise_error(Puppet::ParseError, /unexpected argument type String/)
+ expect { new_hash = scope.function_merge([{}, '2'])}.to raise_error(Puppet::ParseError, /unexpected argument type String/)
+ expect { new_hash = scope.function_merge([{}, 2])}.to raise_error(Puppet::ParseError, /unexpected argument type Fixnum/)
+ end
+ it 'should accept empty strings as puppet undef' do
+ expect { new_hash = scope.function_merge([{}, ''])}.not_to raise_error(Puppet::ParseError, /unexpected argument type String/)
end
+
it 'should be able to merge two hashes' do
new_hash = scope.function_merge([{'one' => '1', 'two' => '1'}, {'two' => '2', 'three' => '2'}])
new_hash['one'].should == '1'
new_hash['two'].should == '2'
new_hash['three'].should == '2'
end
+
it 'should merge multiple hashes' do
hash = scope.function_merge([{'one' => 1}, {'one' => '2'}, {'one' => '3'}])
hash['one'].should == '3'
end
+
it 'should accept empty hashes' do
scope.function_merge([{},{},{}]).should == {}
end
-
end
-
end
diff --git a/spec/unit/puppet/parser/functions/min_spec.rb b/spec/unit/puppet/parser/functions/min_spec.rb
new file mode 100755
index 0000000..71d593e
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/min_spec.rb
@@ -0,0 +1,27 @@
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
+
+describe "the min function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("min").should == "function_min"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_min([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should be able to compare strings" do
+ scope.function_min(["albatross","dog","horse"]).should(eq("albatross"))
+ end
+
+ it "should be able to compare numbers" do
+ scope.function_min([6,8,4]).should(eq(4))
+ end
+
+ it "should be able to compare a number with a stringified number" do
+ scope.function_min([1,"2"]).should(eq(1))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/num2bool_spec.rb b/spec/unit/puppet/parser/functions/num2bool_spec.rb
index 6585273..b56196d 100644
--- a/spec/unit/puppet/parser/functions/num2bool_spec.rb
+++ b/spec/unit/puppet/parser/functions/num2bool_spec.rb
@@ -1,31 +1,67 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the num2bool function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("num2bool").should == "function_num2bool"
end
- before :each do
- @scope = Puppet::Parser::Scope.new
+ it "should raise a ParseError if there are no arguments" do
+ lambda { scope.function_num2bool([]) }.should( raise_error(Puppet::ParseError))
end
- it "should exist" do
- Puppet::Parser::Functions.function("num2bool").should == "function_num2bool"
+ it "should raise a ParseError if there are more than 1 arguments" do
+ lambda { scope.function_num2bool(["foo","bar"]) }.should( raise_error(Puppet::ParseError))
end
- it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_num2bool([]) }.should( raise_error(Puppet::ParseError))
+ it "should raise a ParseError if passed something non-numeric" do
+ lambda { scope.function_num2bool(["xyzzy"]) }.should( raise_error(Puppet::ParseError))
end
- it "should return true if 1" do
- result = @scope.function_num2bool(["1"])
+ it "should return true if passed string 1" do
+ result = scope.function_num2bool(["1"])
result.should(be_true)
end
- it "should return false if 0" do
- result = @scope.function_num2bool(["0"])
+ it "should return true if passed string 1.5" do
+ result = scope.function_num2bool(["1.5"])
+ result.should(be_true)
+ end
+
+ it "should return true if passed number 1" do
+ result = scope.function_num2bool([1])
+ result.should(be_true)
+ end
+
+ it "should return false if passed string 0" do
+ result = scope.function_num2bool(["0"])
result.should(be_false)
end
+ it "should return false if passed number 0" do
+ result = scope.function_num2bool([0])
+ result.should(be_false)
+ end
+
+ it "should return false if passed string -1" do
+ result = scope.function_num2bool(["-1"])
+ result.should(be_false)
+ end
+
+ it "should return false if passed string -1.5" do
+ result = scope.function_num2bool(["-1.5"])
+ result.should(be_false)
+ end
+
+ it "should return false if passed number -1" do
+ result = scope.function_num2bool([-1])
+ result.should(be_false)
+ end
+
+ it "should return false if passed float -1.5" do
+ result = scope.function_num2bool([-1.5])
+ result.should(be_false)
+ end
end
diff --git a/spec/unit/puppet/parser/functions/parsejson_spec.rb b/spec/unit/puppet/parser/functions/parsejson_spec.rb
index 26eea36..f179ac1 100644
--- a/spec/unit/puppet/parser/functions/parsejson_spec.rb
+++ b/spec/unit/puppet/parser/functions/parsejson_spec.rb
@@ -1,29 +1,22 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the parsejson function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("parsejson").should == "function_parsejson"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_parsejson([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_parsejson([]) }.should( raise_error(Puppet::ParseError))
end
it "should convert JSON to a data structure" do
json = <<-EOS
["aaa","bbb","ccc"]
EOS
- result = @scope.function_parsejson([json])
+ result = scope.function_parsejson([json])
result.should(eq(['aaa','bbb','ccc']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/parseyaml_spec.rb b/spec/unit/puppet/parser/functions/parseyaml_spec.rb
index f9cb049..0c7aea8 100644
--- a/spec/unit/puppet/parser/functions/parseyaml_spec.rb
+++ b/spec/unit/puppet/parser/functions/parseyaml_spec.rb
@@ -1,21 +1,15 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the parseyaml function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("parseyaml").should == "function_parseyaml"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_parseyaml([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_parseyaml([]) }.should( raise_error(Puppet::ParseError))
end
it "should convert YAML to a data structure" do
@@ -24,8 +18,7 @@ describe "the parseyaml function" do
- bbb
- ccc
EOS
- result = @scope.function_parseyaml([yaml])
+ result = scope.function_parseyaml([yaml])
result.should(eq(['aaa','bbb','ccc']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/pick_spec.rb b/spec/unit/puppet/parser/functions/pick_spec.rb
new file mode 100644
index 0000000..761db6b
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/pick_spec.rb
@@ -0,0 +1,34 @@
+#!/usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the pick function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("pick").should == "function_pick"
+ end
+
+ it 'should return the correct value' do
+ scope.function_pick(['first', 'second']).should == 'first'
+ end
+
+ it 'should return the correct value if the first value is empty' do
+ scope.function_pick(['', 'second']).should == 'second'
+ end
+
+ it 'should remove empty string values' do
+ scope.function_pick(['', 'first']).should == 'first'
+ end
+
+ it 'should remove :undef values' do
+ scope.function_pick([:undef, 'first']).should == 'first'
+ end
+
+ it 'should remove :undefined values' do
+ scope.function_pick([:undefined, 'first']).should == 'first'
+ end
+
+ it 'should error if no values are passed' do
+ expect { scope.function_pick([]) }.to raise_error(Puppet::Error, /Must provide non empty value./)
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/prefix_spec.rb b/spec/unit/puppet/parser/functions/prefix_spec.rb
index a0cbcab..5cf592b 100644
--- a/spec/unit/puppet/parser/functions/prefix_spec.rb
+++ b/spec/unit/puppet/parser/functions/prefix_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the prefix function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("prefix").should == "function_prefix"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_prefix([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_prefix([]) }.should( raise_error(Puppet::ParseError))
end
it "should return a prefixed array" do
- result = @scope.function_prefix([['a','b','c'], 'p'])
+ result = scope.function_prefix([['a','b','c'], 'p'])
result.should(eq(['pa','pb','pc']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/range_spec.rb b/spec/unit/puppet/parser/functions/range_spec.rb
index 24cc391..5eb290f 100644
--- a/spec/unit/puppet/parser/functions/range_spec.rb
+++ b/spec/unit/puppet/parser/functions/range_spec.rb
@@ -1,60 +1,64 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the range function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("range").should == "function_range"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_range([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_range([]) }.should( raise_error(Puppet::ParseError))
end
it "should return a letter range" do
- result = @scope.function_range(["a","d"])
+ result = scope.function_range(["a","d"])
result.should(eq(['a','b','c','d']))
end
it "should return a letter range given a step of 1" do
- result = @scope.function_range(["a","d","1"])
+ result = scope.function_range(["a","d","1"])
result.should(eq(['a','b','c','d']))
end
it "should return a stepped letter range" do
- result = @scope.function_range(["a","d","2"])
+ result = scope.function_range(["a","d","2"])
result.should(eq(['a','c']))
end
it "should return a stepped letter range given a negative step" do
- result = @scope.function_range(["1","4","-2"])
+ result = scope.function_range(["a","d","-2"])
result.should(eq(['a','c']))
end
it "should return a number range" do
- result = @scope.function_range(["1","4"])
+ result = scope.function_range(["1","4"])
result.should(eq([1,2,3,4]))
end
+ it "should work with padded hostname like strings" do
+ expected = ("host01".."host10").to_a
+ scope.function_range(["host01","host10"]).should eq expected
+ end
+
+ it "should coerce zero padded digits to integers" do
+ expected = (0..10).to_a
+ scope.function_range(["00", "10"]).should eq expected
+ end
+
it "should return a number range given a step of 1" do
- result = @scope.function_range(["1","4","1"])
+ result = scope.function_range(["1","4","1"])
result.should(eq([1,2,3,4]))
end
it "should return a stepped number range" do
- result = @scope.function_range(["1","4","2"])
+ result = scope.function_range(["1","4","2"])
result.should(eq([1,3]))
end
it "should return a stepped number range given a negative step" do
- result = @scope.function_range(["1","4","-2"])
+ result = scope.function_range(["1","4","-2"])
result.should(eq([1,3]))
end
diff --git a/spec/unit/puppet/parser/functions/reject_spec.rb b/spec/unit/puppet/parser/functions/reject_spec.rb
new file mode 100755
index 0000000..f2cb741
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/reject_spec.rb
@@ -0,0 +1,20 @@
+#!/usr/bin/env ruby
+
+require 'spec_helper'
+
+describe "the reject function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("reject").should == "function_reject"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_reject([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should reject contents from an array" do
+ result = scope.function_reject([["1111", "aaabbb","bbbccc","dddeee"], "bbb"])
+ result.should(eq(["1111", "dddeee"]))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/reverse_spec.rb b/spec/unit/puppet/parser/functions/reverse_spec.rb
index 4fa50e4..1b59206 100644
--- a/spec/unit/puppet/parser/functions/reverse_spec.rb
+++ b/spec/unit/puppet/parser/functions/reverse_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the reverse function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("reverse").should == "function_reverse"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_reverse([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_reverse([]) }.should( raise_error(Puppet::ParseError))
end
it "should reverse a string" do
- result = @scope.function_reverse(["asdfghijkl"])
+ result = scope.function_reverse(["asdfghijkl"])
result.should(eq('lkjihgfdsa'))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/rstrip_spec.rb b/spec/unit/puppet/parser/functions/rstrip_spec.rb
index af8cc12..d90de1d 100644
--- a/spec/unit/puppet/parser/functions/rstrip_spec.rb
+++ b/spec/unit/puppet/parser/functions/rstrip_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the rstrip function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("rstrip").should == "function_rstrip"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_rstrip([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_rstrip([]) }.should( raise_error(Puppet::ParseError))
end
it "should rstrip a string" do
- result = @scope.function_rstrip(["asdf "])
+ result = scope.function_rstrip(["asdf "])
result.should(eq('asdf'))
end
it "should rstrip each element in an array" do
- result = @scope.function_rstrip([["a ","b ", "c "]])
+ result = scope.function_rstrip([["a ","b ", "c "]])
result.should(eq(['a','b','c']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/shuffle_spec.rb b/spec/unit/puppet/parser/functions/shuffle_spec.rb
index f04fda5..93346d5 100644
--- a/spec/unit/puppet/parser/functions/shuffle_spec.rb
+++ b/spec/unit/puppet/parser/functions/shuffle_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the shuffle function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("shuffle").should == "function_shuffle"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_shuffle([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_shuffle([]) }.should( raise_error(Puppet::ParseError))
end
it "should shuffle a string and the result should be the same size" do
- result = @scope.function_shuffle(["asdf"])
+ result = scope.function_shuffle(["asdf"])
result.size.should(eq(4))
end
it "should shuffle a string but the sorted contents should still be the same" do
- result = @scope.function_shuffle(["adfs"])
+ result = scope.function_shuffle(["adfs"])
result.split("").sort.join("").should(eq("adfs"))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/size_spec.rb b/spec/unit/puppet/parser/functions/size_spec.rb
index ccaa335..b1c435a 100644
--- a/spec/unit/puppet/parser/functions/size_spec.rb
+++ b/spec/unit/puppet/parser/functions/size_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the size function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("size").should == "function_size"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_size([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_size([]) }.should( raise_error(Puppet::ParseError))
end
it "should return the size of a string" do
- result = @scope.function_size(["asdf"])
+ result = scope.function_size(["asdf"])
result.should(eq(4))
end
it "should return the size of an array" do
- result = @scope.function_size([["a","b","c"]])
+ result = scope.function_size([["a","b","c"]])
result.should(eq(3))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/sort_spec.rb b/spec/unit/puppet/parser/functions/sort_spec.rb
index fbe3073..3187a5a 100644
--- a/spec/unit/puppet/parser/functions/sort_spec.rb
+++ b/spec/unit/puppet/parser/functions/sort_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the sort function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("sort").should == "function_sort"
end
it "should raise a ParseError if there is not 1 arguments" do
- lambda { @scope.function_sort(['','']) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_sort(['','']) }.should( raise_error(Puppet::ParseError))
end
it "should sort an array" do
- result = @scope.function_sort([["a","c","b"]])
+ result = scope.function_sort([["a","c","b"]])
result.should(eq(['a','b','c']))
end
it "should sort a string" do
- result = @scope.function_sort(["acb"])
+ result = scope.function_sort(["acb"])
result.should(eq('abc'))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/squeeze_spec.rb b/spec/unit/puppet/parser/functions/squeeze_spec.rb
index 9355ad2..60e5a30 100644
--- a/spec/unit/puppet/parser/functions/squeeze_spec.rb
+++ b/spec/unit/puppet/parser/functions/squeeze_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the squeeze function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("squeeze").should == "function_squeeze"
end
it "should raise a ParseError if there is less than 2 arguments" do
- lambda { @scope.function_squeeze([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_squeeze([]) }.should( raise_error(Puppet::ParseError))
end
it "should squeeze a string" do
- result = @scope.function_squeeze(["aaabbbbcccc"])
+ result = scope.function_squeeze(["aaabbbbcccc"])
result.should(eq('abc'))
end
it "should squeeze all elements in an array" do
- result = @scope.function_squeeze([["aaabbbbcccc","dddfff"]])
+ result = scope.function_squeeze([["aaabbbbcccc","dddfff"]])
result.should(eq(['abc','df']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/str2bool_spec.rb b/spec/unit/puppet/parser/functions/str2bool_spec.rb
index d7f0ac9..ef6350f 100644
--- a/spec/unit/puppet/parser/functions/str2bool_spec.rb
+++ b/spec/unit/puppet/parser/functions/str2bool_spec.rb
@@ -1,31 +1,31 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the str2bool function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("str2bool").should == "function_str2bool"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_str2bool([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_str2bool([]) }.should( raise_error(Puppet::ParseError))
end
it "should convert string 'true' to true" do
- result = @scope.function_str2bool(["true"])
+ result = scope.function_str2bool(["true"])
result.should(eq(true))
end
it "should convert string 'undef' to false" do
- result = @scope.function_str2bool(["undef"])
+ result = scope.function_str2bool(["undef"])
+ result.should(eq(false))
+ end
+
+ it "should return the boolean it was called with" do
+ result = scope.function_str2bool([true])
+ result.should(eq(true))
+ result = scope.function_str2bool([false])
result.should(eq(false))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb b/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb
new file mode 100644
index 0000000..df8fb8e
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/str2saltedsha512_spec.rb
@@ -0,0 +1,45 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the str2saltedsha512 function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("str2saltedsha512").should == "function_str2saltedsha512"
+ end
+
+ it "should raise a ParseError if there is less than 1 argument" do
+ expect { scope.function_str2saltedsha512([]) }.to( raise_error(Puppet::ParseError) )
+ end
+
+ it "should raise a ParseError if there is more than 1 argument" do
+ expect { scope.function_str2saltedsha512(['foo', 'bar', 'baz']) }.to( raise_error(Puppet::ParseError) )
+ end
+
+ it "should return a salted-sha512 password hash 136 characters in length" do
+ result = scope.function_str2saltedsha512(["password"])
+ result.length.should(eq(136))
+ end
+
+ it "should raise an error if you pass a non-string password" do
+ expect { scope.function_str2saltedsha512([1234]) }.to( raise_error(Puppet::ParseError) )
+ end
+
+ it "should generate a valid password" do
+ # Allow the function to generate a password based on the string 'password'
+ password_hash = scope.function_str2saltedsha512(["password"])
+
+ # Separate the Salt and Password from the Password Hash
+ salt = password_hash[0..7]
+ password = password_hash[8..-1]
+
+ # Convert the Salt and Password from Hex to Binary Data
+ str_salt = Array(salt.lines).pack('H*')
+ str_password = Array(password.lines).pack('H*')
+
+ # Combine the Binary Salt with 'password' and compare the end result
+ saltedpass = Digest::SHA512.digest(str_salt + 'password')
+ result = (str_salt + saltedpass).unpack('H*')[0]
+ result.should == password_hash
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/strftime_spec.rb b/spec/unit/puppet/parser/functions/strftime_spec.rb
index f7a2cd9..df42b6f 100644
--- a/spec/unit/puppet/parser/functions/strftime_spec.rb
+++ b/spec/unit/puppet/parser/functions/strftime_spec.rb
@@ -1,36 +1,29 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the strftime function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("strftime").should == "function_strftime"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_strftime([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_strftime([]) }.should( raise_error(Puppet::ParseError))
end
it "using %s should be higher then when I wrote this test" do
- result = @scope.function_strftime(["%s"])
+ result = scope.function_strftime(["%s"])
result.to_i.should(be > 1311953157)
end
it "using %s should be lower then 1.5 trillion" do
- result = @scope.function_strftime(["%s"])
+ result = scope.function_strftime(["%s"])
result.to_i.should(be < 1500000000)
end
it "should return a date when given %Y-%m-%d" do
- result = @scope.function_strftime(["%Y-%m-%d"])
+ result = scope.function_strftime(["%Y-%m-%d"])
result.should =~ /^\d{4}-\d{2}-\d{2}$/
end
-
end
diff --git a/spec/unit/puppet/parser/functions/strip_spec.rb b/spec/unit/puppet/parser/functions/strip_spec.rb
index 48a52dd..fccdd26 100644
--- a/spec/unit/puppet/parser/functions/strip_spec.rb
+++ b/spec/unit/puppet/parser/functions/strip_spec.rb
@@ -1,26 +1,18 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the strip function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
-
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("strip").should == "function_strip"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_strip([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_strip([]) }.should( raise_error(Puppet::ParseError))
end
it "should strip a string" do
- result = @scope.function_strip([" ab cd "])
+ result = scope.function_strip([" ab cd "])
result.should(eq('ab cd'))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/suffix_spec.rb b/spec/unit/puppet/parser/functions/suffix_spec.rb
new file mode 100644
index 0000000..c28f719
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/suffix_spec.rb
@@ -0,0 +1,19 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the suffix function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("suffix").should == "function_suffix"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_suffix([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should return a suffixed array" do
+ result = scope.function_suffix([['a','b','c'], 'p'])
+ result.should(eq(['ap','bp','cp']))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/swapcase_spec.rb b/spec/unit/puppet/parser/functions/swapcase_spec.rb
index 2686054..808b415 100644
--- a/spec/unit/puppet/parser/functions/swapcase_spec.rb
+++ b/spec/unit/puppet/parser/functions/swapcase_spec.rb
@@ -1,26 +1,19 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the swapcase function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("swapcase").should == "function_swapcase"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_swapcase([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_swapcase([]) }.should( raise_error(Puppet::ParseError))
end
it "should swapcase a string" do
- result = @scope.function_swapcase(["aaBBccDD"])
+ result = scope.function_swapcase(["aaBBccDD"])
result.should(eq('AAbbCCdd'))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/time_spec.rb b/spec/unit/puppet/parser/functions/time_spec.rb
index 666e8e0..e9fb76e 100644
--- a/spec/unit/puppet/parser/functions/time_spec.rb
+++ b/spec/unit/puppet/parser/functions/time_spec.rb
@@ -1,36 +1,29 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the time function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("time").should == "function_time"
end
it "should raise a ParseError if there is more than 2 arguments" do
- lambda { @scope.function_time(['','']) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_time(['','']) }.should( raise_error(Puppet::ParseError))
end
it "should return a number" do
- result = @scope.function_time([])
- result.class.should(eq(Fixnum))
+ result = scope.function_time([])
+ result.should be_an(Integer)
end
it "should be higher then when I wrote this test" do
- result = @scope.function_time([])
+ result = scope.function_time([])
result.should(be > 1311953157)
end
it "should be lower then 1.5 trillion" do
- result = @scope.function_time([])
+ result = scope.function_time([])
result.should(be < 1500000000)
end
-
end
diff --git a/spec/unit/puppet/parser/functions/to_bytes_spec.rb b/spec/unit/puppet/parser/functions/to_bytes_spec.rb
new file mode 100755
index 0000000..d1ea4c8
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/to_bytes_spec.rb
@@ -0,0 +1,58 @@
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
+
+describe "the to_bytes function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("to_bytes").should == "function_to_bytes"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_to_bytes([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should convert kB to B" do
+ result = scope.function_to_bytes(["4 kB"])
+ result.should(eq(4096))
+ end
+
+ it "should work without B in unit" do
+ result = scope.function_to_bytes(["4 k"])
+ result.should(eq(4096))
+ end
+
+ it "should work without a space before unit" do
+ result = scope.function_to_bytes(["4k"])
+ result.should(eq(4096))
+ end
+
+ it "should work without a unit" do
+ result = scope.function_to_bytes(["5678"])
+ result.should(eq(5678))
+ end
+
+ it "should convert fractions" do
+ result = scope.function_to_bytes(["1.5 kB"])
+ result.should(eq(1536))
+ end
+
+ it "should convert scientific notation" do
+ result = scope.function_to_bytes(["1.5e2 B"])
+ result.should(eq(150))
+ end
+
+ it "should do nothing with a positive number" do
+ result = scope.function_to_bytes([5678])
+ result.should(eq(5678))
+ end
+
+ it "should should raise a ParseError if input isn't a number" do
+ lambda { scope.function_to_bytes(["foo"]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should should raise a ParseError if prefix is unknown" do
+ lambda { scope.function_to_bytes(["5 uB"]) }.should( raise_error(Puppet::ParseError))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/type_spec.rb b/spec/unit/puppet/parser/functions/type_spec.rb
index e3c28ed..8fec88f 100644
--- a/spec/unit/puppet/parser/functions/type_spec.rb
+++ b/spec/unit/puppet/parser/functions/type_spec.rb
@@ -1,51 +1,43 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the type function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
-
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("type").should == "function_type"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_type([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_type([]) }.should( raise_error(Puppet::ParseError))
end
it "should return string when given a string" do
- result = @scope.function_type(["aaabbbbcccc"])
+ result = scope.function_type(["aaabbbbcccc"])
result.should(eq('string'))
end
it "should return array when given an array" do
- result = @scope.function_type([["aaabbbbcccc","asdf"]])
+ result = scope.function_type([["aaabbbbcccc","asdf"]])
result.should(eq('array'))
end
it "should return hash when given a hash" do
- result = @scope.function_type([{"a"=>1,"b"=>2}])
+ result = scope.function_type([{"a"=>1,"b"=>2}])
result.should(eq('hash'))
end
it "should return integer when given an integer" do
- result = @scope.function_type(["1"])
+ result = scope.function_type(["1"])
result.should(eq('integer'))
end
it "should return float when given a float" do
- result = @scope.function_type(["1.34"])
+ result = scope.function_type(["1.34"])
result.should(eq('float'))
end
it "should return boolean when given a boolean" do
- result = @scope.function_type([true])
+ result = scope.function_type([true])
result.should(eq('boolean'))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/union_spec.rb b/spec/unit/puppet/parser/functions/union_spec.rb
new file mode 100644
index 0000000..0d282ca
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/union_spec.rb
@@ -0,0 +1,19 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the union function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("union").should == "function_union"
+ end
+
+ it "should raise a ParseError if there are fewer than 2 arguments" do
+ lambda { scope.function_union([]) }.should( raise_error(Puppet::ParseError) )
+ end
+
+ it "should join two arrays together" do
+ result = scope.function_union([["a","b","c"],["b","c","d"]])
+ result.should(eq(["a","b","c","d"]))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/unique_spec.rb b/spec/unit/puppet/parser/functions/unique_spec.rb
index 627dc33..5d48d49 100644
--- a/spec/unit/puppet/parser/functions/unique_spec.rb
+++ b/spec/unit/puppet/parser/functions/unique_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the unique function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("unique").should == "function_unique"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_unique([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_unique([]) }.should( raise_error(Puppet::ParseError))
end
it "should remove duplicate elements in a string" do
- result = @scope.function_unique(["aabbc"])
+ result = scope.function_unique(["aabbc"])
result.should(eq('abc'))
end
it "should remove duplicate elements in an array" do
- result = @scope.function_unique([["a","a","b","b","c"]])
+ result = scope.function_unique([["a","a","b","b","c"]])
result.should(eq(['a','b','c']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/upcase_spec.rb b/spec/unit/puppet/parser/functions/upcase_spec.rb
index 5d18846..5db5513 100644
--- a/spec/unit/puppet/parser/functions/upcase_spec.rb
+++ b/spec/unit/puppet/parser/functions/upcase_spec.rb
@@ -1,31 +1,24 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the upcase function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("upcase").should == "function_upcase"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_upcase([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_upcase([]) }.should( raise_error(Puppet::ParseError))
end
it "should upcase a string" do
- result = @scope.function_upcase(["abc"])
+ result = scope.function_upcase(["abc"])
result.should(eq('ABC'))
end
it "should do nothing if a string is already upcase" do
- result = @scope.function_upcase(["ABC"])
+ result = scope.function_upcase(["ABC"])
result.should(eq('ABC'))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/uriescape_spec.rb b/spec/unit/puppet/parser/functions/uriescape_spec.rb
new file mode 100644
index 0000000..371de46
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/uriescape_spec.rb
@@ -0,0 +1,24 @@
+#! /usr/bin/env ruby -S rspec
+require 'spec_helper'
+
+describe "the uriescape function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("uriescape").should == "function_uriescape"
+ end
+
+ it "should raise a ParseError if there is less than 1 arguments" do
+ lambda { scope.function_uriescape([]) }.should( raise_error(Puppet::ParseError))
+ end
+
+ it "should uriescape a string" do
+ result = scope.function_uriescape([":/?#[]@!$&'()*+,;= "])
+ result.should(eq('%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D%20'))
+ end
+
+ it "should do nothing if a string is already safe" do
+ result = scope.function_uriescape(["ABCdef"])
+ result.should(eq('ABCdef'))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb b/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb
new file mode 100644
index 0000000..08aaf78
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_absolute_path_spec.rb
@@ -0,0 +1,83 @@
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:validate_absolute_path) do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ # The subject of these examples is the method itself.
+ subject do
+ # This makes sure the function is loaded within each test
+ function_name = Puppet::Parser::Functions.function(:validate_absolute_path)
+ scope.method(function_name)
+ end
+
+ describe "Valid Paths" do
+ def self.valid_paths
+ %w{
+ C:/
+ C:\\
+ C:\\WINDOWS\\System32
+ C:/windows/system32
+ X:/foo/bar
+ X:\\foo\\bar
+ /var/tmp
+ /var/lib/puppet
+ /var/opt/../lib/puppet
+ }
+ end
+
+ context "Without Puppet::Util.absolute_path? (e.g. Puppet <= 2.6)" do
+ before :each do
+ # The intent here is to mock Puppet to behave like Puppet 2.6 does.
+ # Puppet 2.6 does not have the absolute_path? method. This is only a
+ # convenience test, stdlib should be run with the Puppet 2.6.x in the
+ # $LOAD_PATH in addition to 2.7.x and master.
+ Puppet::Util.expects(:respond_to?).with(:absolute_path?).returns(false)
+ end
+ valid_paths.each do |path|
+ it "validate_absolute_path(#{path.inspect}) should not fail" do
+ expect { subject.call [path] }.not_to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ context "Puppet without mocking" do
+ valid_paths.each do |path|
+ it "validate_absolute_path(#{path.inspect}) should not fail" do
+ expect { subject.call [path] }.not_to raise_error Puppet::ParseError
+ end
+ end
+ end
+ end
+
+ describe 'Invalid paths' do
+ context 'Garbage inputs' do
+ [
+ nil,
+ [ nil ],
+ { 'foo' => 'bar' },
+ { },
+ '',
+ ].each do |path|
+ it "validate_absolute_path(#{path.inspect}) should fail" do
+ expect { subject.call [path] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ context 'Relative paths' do
+ %w{
+ relative1
+ .
+ ..
+ ./foo
+ ../foo
+ etc/puppetlabs/puppet
+ opt/puppet/bin
+ }.each do |path|
+ it "validate_absolute_path(#{path.inspect}) should fail" do
+ expect { subject.call [path] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_array_spec.rb b/spec/unit/puppet/parser/functions/validate_array_spec.rb
index 37ae09d..4b31cfd 100644
--- a/spec/unit/puppet/parser/functions/validate_array_spec.rb
+++ b/spec/unit/puppet/parser/functions/validate_array_spec.rb
@@ -1,41 +1,21 @@
-require 'puppet'
+#! /usr/bin/env ruby -S rspec
-# We don't need this for the basic tests we're doing
-# require 'spec_helper'
+require 'spec_helper'
-# Dan mentioned that Nick recommended the function method call
-# to return the string value for the test description.
-# this will not even try the test if the function cannot be
-# loaded.
describe Puppet::Parser::Functions.function(:validate_array) do
-
- # Pulled from Dan's create_resources function
- def get_scope
- @topscope = Puppet::Parser::Scope.new
- # This is necessary so we don't try to use the compiler to discover our parent.
- @topscope.parent = nil
- @scope = Puppet::Parser::Scope.new
- @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
- @scope.parent = @topscope
- @compiler = @scope.compiler
- end
-
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
describe 'when calling validate_array from puppet' do
%w{ true false }.each do |the_string|
-
it "should not compile when #{the_string} is a string" do
Puppet[:code] = "validate_array('#{the_string}')"
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/)
end
it "should not compile when #{the_string} is a bare word" do
Puppet[:code] = "validate_array(#{the_string})"
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/)
end
-
end
it "should compile when multiple array arguments are passed" do
@@ -44,8 +24,7 @@ describe Puppet::Parser::Functions.function(:validate_array) do
$bar = [ 'one', 'two' ]
validate_array($foo, $bar)
ENDofPUPPETcode
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
it "should not compile when an undef variable is passed" do
@@ -53,11 +32,7 @@ describe Puppet::Parser::Functions.function(:validate_array) do
$foo = undef
validate_array($foo)
ENDofPUPPETcode
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not an Array/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not an Array/)
end
-
end
-
end
-
diff --git a/spec/unit/puppet/parser/functions/validate_augeas_spec.rb b/spec/unit/puppet/parser/functions/validate_augeas_spec.rb
new file mode 100644
index 0000000..ab5c140
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_augeas_spec.rb
@@ -0,0 +1,102 @@
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:validate_augeas), :if => Puppet.features.augeas? do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ # The subject of these examplres is the method itself.
+ subject do
+ # This makes sure the function is loaded within each test
+ function_name = Puppet::Parser::Functions.function(:validate_augeas)
+ scope.method(function_name)
+ end
+
+ context 'Using Puppet::Parser::Scope.new' do
+
+ describe 'Garbage inputs' do
+ inputs = [
+ [ nil ],
+ [ [ nil ] ],
+ [ { 'foo' => 'bar' } ],
+ [ { } ],
+ [ '' ],
+ [ "one", "one", "MSG to User", "4th arg" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_augeas(#{input.inspect}) should fail" do
+ expect { subject.call [input] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ describe 'Valid inputs' do
+ inputs = [
+ [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns' ],
+ [ "proc /proc proc nodev,noexec,nosuid 0 0\n", 'Fstab.lns'],
+ ]
+
+ inputs.each do |input|
+ it "validate_augeas(#{input.inspect}) should not fail" do
+ expect { subject.call input }.not_to raise_error
+ end
+ end
+ end
+
+ describe "Valid inputs which should raise an exception without a message" do
+ # The intent here is to make sure valid inputs raise exceptions when they
+ # don't specify an error message to display. This is the behvior in
+ # 2.2.x and prior.
+ inputs = [
+ [ "root:x:0:0:root\n", 'Passwd.lns' ],
+ [ "127.0.1.1\n", 'Hosts.lns' ],
+ ]
+
+ inputs.each do |input|
+ it "validate_augeas(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /validate_augeas.*?matched less than it should/
+ end
+ end
+ end
+
+ describe "Nicer Error Messages" do
+ # The intent here is to make sure the function returns the 3rd argument
+ # in the exception thrown
+ inputs = [
+ [ "root:x:0:0:root\n", 'Passwd.lns', [], 'Failed to validate passwd content' ],
+ [ "127.0.1.1\n", 'Hosts.lns', [], 'Wrong hosts content' ],
+ ]
+
+ inputs.each do |input|
+ it "validate_augeas(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /#{input[2]}/
+ end
+ end
+ end
+
+ describe "Passing simple unit tests" do
+ inputs = [
+ [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']],
+ [ "root:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']],
+ ]
+
+ inputs.each do |input|
+ it "validate_augeas(#{input.inspect}) should fail" do
+ expect { subject.call input }.not_to raise_error
+ end
+ end
+ end
+
+ describe "Failing simple unit tests" do
+ inputs = [
+ [ "foobar:x:0:0:root:/root:/bin/bash\n", 'Passwd.lns', ['$file/foobar']],
+ [ "root:x:0:0:root:/root:/bin/sh\n", 'Passwd.lns', ['$file/root/shell[.="/bin/sh"]', 'foobar']],
+ ]
+
+ inputs.each do |input|
+ it "validate_augeas(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /testing path/
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_bool_spec.rb b/spec/unit/puppet/parser/functions/validate_bool_spec.rb
index e95c396..261fb23 100644
--- a/spec/unit/puppet/parser/functions/validate_bool_spec.rb
+++ b/spec/unit/puppet/parser/functions/validate_bool_spec.rb
@@ -1,53 +1,33 @@
-require 'puppet'
+#! /usr/bin/env/ruby -S rspec
-# We don't need this for the basic tests we're doing
-# require 'spec_helper'
+require 'spec_helper'
-# Dan mentioned that Nick recommended the function method call
-# to return the string value for the test description.
-# this will not even try the test if the function cannot be
-# loaded.
describe Puppet::Parser::Functions.function(:validate_bool) do
-
- # Pulled from Dan's create_resources function
- def get_scope
- @topscope = Puppet::Parser::Scope.new
- # This is necessary so we don't try to use the compiler to discover our parent.
- @topscope.parent = nil
- @scope = Puppet::Parser::Scope.new
- @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
- @scope.parent = @topscope
- @compiler = @scope.compiler
- end
-
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
describe 'when calling validate_bool from puppet' do
%w{ true false }.each do |the_string|
it "should not compile when #{the_string} is a string" do
Puppet[:code] = "validate_bool('#{the_string}')"
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/)
end
it "should compile when #{the_string} is a bare word" do
Puppet[:code] = "validate_bool(#{the_string})"
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
end
it "should not compile when an arbitrary string is passed" do
Puppet[:code] = 'validate_bool("jeff and dan are awesome")'
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/)
end
it "should not compile when no arguments are passed" do
Puppet[:code] = 'validate_bool()'
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /wrong number of arguments/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /wrong number of arguments/)
end
it "should compile when multiple boolean arguments are passed" do
@@ -56,8 +36,7 @@ describe Puppet::Parser::Functions.function(:validate_bool) do
$bar = false
validate_bool($foo, $bar, true, false)
ENDofPUPPETcode
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
it "should compile when multiple boolean arguments are passed" do
@@ -66,11 +45,7 @@ describe Puppet::Parser::Functions.function(:validate_bool) do
$bar = false
validate_bool($foo, $bar, true, false, 'jeff')
ENDofPUPPETcode
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a boolean/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a boolean/)
end
-
end
-
end
-
diff --git a/spec/unit/puppet/parser/functions/validate_cmd_spec.rb b/spec/unit/puppet/parser/functions/validate_cmd_spec.rb
new file mode 100644
index 0000000..69ea7f4
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_cmd_spec.rb
@@ -0,0 +1,81 @@
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:validate_cmd) do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ # The subject of these examplres is the method itself.
+ subject do
+ # This makes sure the function is loaded within each test
+ function_name = Puppet::Parser::Functions.function(:validate_cmd)
+ scope.method(function_name)
+ end
+
+ context 'Using Puppet::Parser::Scope.new' do
+
+ describe 'Garbage inputs' do
+ inputs = [
+ [ nil ],
+ [ [ nil ] ],
+ [ { 'foo' => 'bar' } ],
+ [ { } ],
+ [ '' ],
+ [ "one", "one", "MSG to User", "4th arg" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_cmd(#{input.inspect}) should fail" do
+ expect { subject.call [input] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ describe 'Valid inputs' do
+ inputs = [
+ [ '/full/path/to/something', '/bin/echo' ],
+ [ '/full/path/to/something', '/bin/cat' ],
+ ]
+
+ inputs.each do |input|
+ it "validate_cmd(#{input.inspect}) should not fail" do
+ expect { subject.call input }.not_to raise_error
+ end
+ end
+ end
+
+ describe "Valid inputs which should raise an exception without a message" do
+ # The intent here is to make sure valid inputs raise exceptions when they
+ # don't specify an error message to display. This is the behvior in
+ # 2.2.x and prior.
+ inputs = [
+ [ "hello", "/bin/false" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_cmd(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /validate_cmd.*?failed to validate content with command/
+ end
+ end
+ end
+
+ describe "Nicer Error Messages" do
+ # The intent here is to make sure the function returns the 3rd argument
+ # in the exception thrown
+ inputs = [
+ [ "hello", [ "bye", "later", "adios" ], "MSG to User" ],
+ [ "greetings", "salutations", "Error, greetings does not match salutations" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_cmd(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /#{input[2]}/
+ end
+ end
+ end
+
+ describe "Test output message" do
+ it "validate_cmd('whatever', 'kthnksbye') should fail" do
+ expect { subject.call ['whatever', 'kthnksbye'] }.to raise_error /kthnksbye.* returned 1/
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_hash_spec.rb b/spec/unit/puppet/parser/functions/validate_hash_spec.rb
index 8cc0b3d..a0c35c2 100644
--- a/spec/unit/puppet/parser/functions/validate_hash_spec.rb
+++ b/spec/unit/puppet/parser/functions/validate_hash_spec.rb
@@ -1,24 +1,9 @@
-require 'puppet'
+#! /usr/bin/env ruby -S rspec
-# We don't need this for the basic tests we're doing
-# require 'spec_helper'
+require 'spec_helper'
-# Dan mentioned that Nick recommended the function method call
-# to return the string value for the test description.
-# this will not even try the test if the function cannot be
-# loaded.
describe Puppet::Parser::Functions.function(:validate_hash) do
-
- # Pulled from Dan's create_resources function
- def get_scope
- @topscope = Puppet::Parser::Scope.new
- # This is necessary so we don't try to use the compiler to discover our parent.
- @topscope.parent = nil
- @scope = Puppet::Parser::Scope.new
- @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
- @scope.parent = @topscope
- @compiler = @scope.compiler
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
describe 'when calling validate_hash from puppet' do
@@ -26,14 +11,12 @@ describe Puppet::Parser::Functions.function(:validate_hash) do
it "should not compile when #{the_string} is a string" do
Puppet[:code] = "validate_hash('#{the_string}')"
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/)
end
it "should not compile when #{the_string} is a bare word" do
Puppet[:code] = "validate_hash(#{the_string})"
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/)
end
end
@@ -44,8 +27,7 @@ describe Puppet::Parser::Functions.function(:validate_hash) do
$bar = { 'one' => 'two' }
validate_hash($foo, $bar)
ENDofPUPPETcode
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
it "should not compile when an undef variable is passed" do
@@ -53,11 +35,9 @@ describe Puppet::Parser::Functions.function(:validate_hash) do
$foo = undef
validate_hash($foo)
ENDofPUPPETcode
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a Hash/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a Hash/)
end
end
end
-
diff --git a/spec/unit/puppet/parser/functions/validate_re_spec.rb b/spec/unit/puppet/parser/functions/validate_re_spec.rb
new file mode 100644
index 0000000..d189efb
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_re_spec.rb
@@ -0,0 +1,76 @@
+require 'spec_helper'
+
+describe Puppet::Parser::Functions.function(:validate_re) do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ # The subject of these examplres is the method itself.
+ subject do
+ # This makes sure the function is loaded within each test
+ function_name = Puppet::Parser::Functions.function(:validate_re)
+ scope.method(function_name)
+ end
+
+ context 'Using Puppet::Parser::Scope.new' do
+
+ describe 'Garbage inputs' do
+ inputs = [
+ [ nil ],
+ [ [ nil ] ],
+ [ { 'foo' => 'bar' } ],
+ [ { } ],
+ [ '' ],
+ [ "one", "one", "MSG to User", "4th arg" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should fail" do
+ expect { subject.call [input] }.to raise_error Puppet::ParseError
+ end
+ end
+ end
+
+ describe 'Valid inputs' do
+ inputs = [
+ [ '/full/path/to/something', '^/full' ],
+ [ '/full/path/to/something', 'full' ],
+ [ '/full/path/to/something', ['full', 'absent'] ],
+ [ '/full/path/to/something', ['full', 'absent'], 'Message to the user' ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should not fail" do
+ expect { subject.call input }.not_to raise_error
+ end
+ end
+ end
+ describe "Valid inputs which should raise an exception without a message" do
+ # The intent here is to make sure valid inputs raise exceptions when they
+ # don't specify an error message to display. This is the behvior in
+ # 2.2.x and prior.
+ inputs = [
+ [ "hello", [ "bye", "later", "adios" ] ],
+ [ "greetings", "salutations" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /validate_re.*?does not match/
+ end
+ end
+ end
+ describe "Nicer Error Messages" do
+ # The intent here is to make sure the function returns the 3rd argument
+ # in the exception thrown
+ inputs = [
+ [ "hello", [ "bye", "later", "adios" ], "MSG to User" ],
+ [ "greetings", "salutations", "Error, greetings does not match salutations" ],
+ ]
+
+ inputs.each do |input|
+ it "validate_re(#{input.inspect}) should fail" do
+ expect { subject.call input }.to raise_error /#{input[2]}/
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_slength_spec.rb b/spec/unit/puppet/parser/functions/validate_slength_spec.rb
new file mode 100755
index 0000000..b363e7a
--- /dev/null
+++ b/spec/unit/puppet/parser/functions/validate_slength_spec.rb
@@ -0,0 +1,48 @@
+#! /usr/bin/env ruby -S rspec
+
+require 'spec_helper'
+
+describe "the validate_slength function" do
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
+
+ it "should exist" do
+ Puppet::Parser::Functions.function("validate_slength").should == "function_validate_slength"
+ end
+
+ it "should raise a ParseError if there is less than 2 arguments" do
+ expect { scope.function_validate_slength([]) }.to(raise_error(Puppet::ParseError))
+ expect { scope.function_validate_slength(["asdf"]) }.to(raise_error(Puppet::ParseError))
+ end
+
+ it "should raise a ParseError if argument 2 doesn't convert to a fixnum" do
+ expect { scope.function_validate_slength(["moo",["2"]]) }.to(raise_error(Puppet::ParseError, /Couldn't convert whatever you passed/))
+ end
+
+ it "should raise a ParseError if argument 2 converted, but to 0, e.g. a string" do
+ expect { scope.function_validate_slength(["moo","monkey"]) }.to(raise_error(Puppet::ParseError, /please pass a positive number as max_length/))
+ end
+
+ it "should raise a ParseError if argument 2 converted, but to 0" do
+ expect { scope.function_validate_slength(["moo","0"]) }.to(raise_error(Puppet::ParseError, /please pass a positive number as max_length/))
+ end
+
+ it "should fail if string greater then size" do
+ expect { scope.function_validate_slength(["test", 2]) }.to(raise_error(Puppet::ParseError, /It should have been less than or equal to/))
+ end
+
+ it "should fail if you pass an array of something other than strings" do
+ expect { scope.function_validate_slength([["moo",["moo"],Hash.new["moo" => 7]], 7]) }.to(raise_error(Puppet::ParseError, /is not a string, it's a/))
+ end
+
+ it "should fail if you pass something other than a string or array" do
+ expect { scope.function_validate_slength([Hash.new["moo" => "7"],6]) }.to(raise_error(Puppet::ParseError, /please pass a string, or an array of strings/))
+ end
+
+ it "should not fail if string is smaller or equal to size" do
+ expect { scope.function_validate_slength(["test", 5]) }.to_not(raise_error(Puppet::ParseError))
+ end
+
+ it "should not fail if array of string is are all smaller or equal to size" do
+ expect { scope.function_validate_slength([["moo","foo","bar"], 5]) }.to_not(raise_error(Puppet::ParseError))
+ end
+end
diff --git a/spec/unit/puppet/parser/functions/validate_string_spec.rb b/spec/unit/puppet/parser/functions/validate_string_spec.rb
index 92392da..3b4fb3e 100644
--- a/spec/unit/puppet/parser/functions/validate_string_spec.rb
+++ b/spec/unit/puppet/parser/functions/validate_string_spec.rb
@@ -1,24 +1,9 @@
-require 'puppet'
+#! /usr/bin/env ruby -S rspec
-# We don't need this for the basic tests we're doing
-# require 'spec_helper'
+require 'spec_helper'
-# Dan mentioned that Nick recommended the function method call
-# to return the string value for the test description.
-# this will not even try the test if the function cannot be
-# loaded.
describe Puppet::Parser::Functions.function(:validate_string) do
-
- # Pulled from Dan's create_resources function
- def get_scope
- @topscope = Puppet::Parser::Scope.new
- # This is necessary so we don't try to use the compiler to discover our parent.
- @topscope.parent = nil
- @scope = Puppet::Parser::Scope.new
- @scope.compiler = Puppet::Parser::Compiler.new(Puppet::Node.new("floppy", :environment => 'production'))
- @scope.parent = @topscope
- @compiler = @scope.compiler
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
describe 'when calling validate_string from puppet' do
@@ -26,14 +11,12 @@ describe Puppet::Parser::Functions.function(:validate_string) do
it "should compile when #{the_string} is a string" do
Puppet[:code] = "validate_string('#{the_string}')"
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
it "should compile when #{the_string} is a bare word" do
Puppet[:code] = "validate_string(#{the_string})"
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
end
@@ -41,14 +24,12 @@ describe Puppet::Parser::Functions.function(:validate_string) do
%w{ true false }.each do |the_string|
it "should compile when #{the_string} is a string" do
Puppet[:code] = "validate_string('#{the_string}')"
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
it "should not compile when #{the_string} is a bare word" do
Puppet[:code] = "validate_string(#{the_string})"
- get_scope
- expect { @scope.compiler.compile }.should raise_error(Puppet::ParseError, /is not a string/)
+ expect { scope.compiler.compile }.to raise_error(Puppet::ParseError, /is not a string/)
end
end
@@ -58,8 +39,7 @@ describe Puppet::Parser::Functions.function(:validate_string) do
$bar = 'two'
validate_string($foo, $bar)
ENDofPUPPETcode
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
it "should compile when an explicitly undef variable is passed (NOTE THIS MAY NOT BE DESIRABLE)" do
@@ -67,17 +47,14 @@ describe Puppet::Parser::Functions.function(:validate_string) do
$foo = undef
validate_string($foo)
ENDofPUPPETcode
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
it "should compile when an undefined variable is passed (NOTE THIS MAY NOT BE DESIRABLE)" do
Puppet[:code] = <<-'ENDofPUPPETcode'
validate_string($foobarbazishouldnotexist)
ENDofPUPPETcode
- get_scope
- @scope.compiler.compile
+ scope.compiler.compile
end
end
end
-
diff --git a/spec/unit/puppet/parser/functions/values_at_spec.rb b/spec/unit/puppet/parser/functions/values_at_spec.rb
index 6c45316..08e95a5 100644
--- a/spec/unit/puppet/parser/functions/values_at_spec.rb
+++ b/spec/unit/puppet/parser/functions/values_at_spec.rb
@@ -1,45 +1,38 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the values_at function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("values_at").should == "function_values_at"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_values_at([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_values_at([]) }.should( raise_error(Puppet::ParseError))
end
it "should raise a ParseError if you try to use a range where stop is greater then start" do
- lambda { @scope.function_values_at([['a','b'],["3-1"]]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_values_at([['a','b'],["3-1"]]) }.should( raise_error(Puppet::ParseError))
end
it "should return a value at from an array" do
- result = @scope.function_values_at([['a','b','c'],"1"])
+ result = scope.function_values_at([['a','b','c'],"1"])
result.should(eq(['b']))
end
it "should return a value at from an array when passed a range" do
- result = @scope.function_values_at([['a','b','c'],"0-1"])
+ result = scope.function_values_at([['a','b','c'],"0-1"])
result.should(eq(['a','b']))
end
it "should return chosen values from an array when passed number of indexes" do
- result = @scope.function_values_at([['a','b','c'],["0","2"]])
+ result = scope.function_values_at([['a','b','c'],["0","2"]])
result.should(eq(['a','c']))
end
it "should return chosen values from an array when passed ranges and multiple indexes" do
- result = @scope.function_values_at([['a','b','c','d','e','f','g'],["0","2","4-5"]])
+ result = scope.function_values_at([['a','b','c','d','e','f','g'],["0","2","4-5"]])
result.should(eq(['a','c','e','f']))
end
-
end
diff --git a/spec/unit/puppet/parser/functions/values_spec.rb b/spec/unit/puppet/parser/functions/values_spec.rb
index f6eb5b6..14ae417 100644
--- a/spec/unit/puppet/parser/functions/values_spec.rb
+++ b/spec/unit/puppet/parser/functions/values_spec.rb
@@ -1,30 +1,31 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the values function" do
- before :all do
- Puppet::Parser::Functions.autoloader.loadall
- end
-
- before :each do
- @scope = Puppet::Parser::Scope.new
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should exist" do
Puppet::Parser::Functions.function("values").should == "function_values"
end
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_values([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_values([]) }.should( raise_error(Puppet::ParseError))
end
it "should return values from a hash" do
- result = @scope.function_values([{'a'=>'1','b'=>'2','c'=>'3'}])
- result.should(eq(['1','2','3']))
+ result = scope.function_values([{'a'=>'1','b'=>'2','c'=>'3'}])
+ # =~ is the RSpec::Matchers::MatchArray matcher.
+ # A.K.A. "array with same elements" (multiset) matching
+ result.should =~ %w{ 1 2 3 }
end
- it "should return values from a hash" do
- lambda { @scope.function_values([['a','b','c']]) }.should( raise_error(Puppet::ParseError))
+ it "should return a multiset" do
+ result = scope.function_values([{'a'=>'1','b'=>'3','c'=>'3'}])
+ result.should =~ %w{ 1 3 3 }
+ result.should_not =~ %w{ 1 3 }
end
+ it "should raise a ParseError unless a Hash is provided" do
+ lambda { scope.function_values([['a','b','c']]) }.should( raise_error(Puppet::ParseError))
+ end
end
diff --git a/spec/unit/puppet/parser/functions/zip_spec.rb b/spec/unit/puppet/parser/functions/zip_spec.rb
index 074f4df..f45ab17 100644
--- a/spec/unit/puppet/parser/functions/zip_spec.rb
+++ b/spec/unit/puppet/parser/functions/zip_spec.rb
@@ -1,26 +1,15 @@
-#!/usr/bin/env rspec
+#! /usr/bin/env ruby -S rspec
require 'spec_helper'
describe "the zip 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("zip").should == "function_zip"
- end
+ let(:scope) { PuppetlabsSpec::PuppetInternals.scope }
it "should raise a ParseError if there is less than 1 arguments" do
- lambda { @scope.function_zip([]) }.should( raise_error(Puppet::ParseError))
+ lambda { scope.function_zip([]) }.should( raise_error(Puppet::ParseError))
end
it "should be able to zip an array" do
- result = @scope.function_zip([['1','2','3'],['4','5','6']])
+ result = scope.function_zip([['1','2','3'],['4','5','6']])
result.should(eq([["1", "4"], ["2", "5"], ["3", "6"]]))
end
-
end
diff --git a/spec/unit/puppet/provider/file_line/ruby_spec.rb b/spec/unit/puppet/provider/file_line/ruby_spec.rb
index b03fc0e..7857d39 100644
--- a/spec/unit/puppet/provider/file_line/ruby_spec.rb
+++ b/spec/unit/puppet/provider/file_line/ruby_spec.rb
@@ -2,29 +2,126 @@ require 'puppet'
require 'tempfile'
provider_class = Puppet::Type.type(:file_line).provider(:ruby)
describe provider_class do
- before :each do
- tmp = Tempfile.new('tmp')
- @tmpfile = tmp.path
- tmp.close!
- @resource = Puppet::Type::File_line.new(
- {:name => 'foo', :path => @tmpfile, :line => 'foo'}
- )
- @provider = provider_class.new(@resource)
- end
- it 'should detect if the line exists in the file' do
- File.open(@tmpfile, 'w') do |fh|
- fh.write('foo')
+ context "when adding" do
+ before :each do
+ # TODO: these should be ported over to use the PuppetLabs spec_helper
+ # file fixtures once the following pull request has been merged:
+ # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files
+ tmp = Tempfile.new('tmp')
+ @tmpfile = tmp.path
+ tmp.close!
+ @resource = Puppet::Type::File_line.new(
+ {:name => 'foo', :path => @tmpfile, :line => 'foo'}
+ )
+ @provider = provider_class.new(@resource)
+ end
+ it 'should detect if the line exists in the file' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write('foo')
+ end
+ @provider.exists?.should be_true
+ end
+ it 'should detect if the line does not exist in the file' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write('foo1')
+ end
+ @provider.exists?.should be_nil
+ end
+ it 'should append to an existing file when creating' do
+ @provider.create
+ File.read(@tmpfile).chomp.should == 'foo'
end
- @provider.exists?.should be_true
end
- it 'should detect if the line does not exist in the file' do
- File.open(@tmpfile, 'w') do |fh|
- fh.write('foo1')
+
+ context "when matching" do
+ before :each do
+ # TODO: these should be ported over to use the PuppetLabs spec_helper
+ # file fixtures once the following pull request has been merged:
+ # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files
+ tmp = Tempfile.new('tmp')
+ @tmpfile = tmp.path
+ tmp.close!
+ @resource = Puppet::Type::File_line.new(
+ {
+ :name => 'foo',
+ :path => @tmpfile,
+ :line => 'foo = bar',
+ :match => '^foo\s*=.*$',
+ }
+ )
+ @provider = provider_class.new(@resource)
+ end
+
+ it 'should raise an error if more than one line matches, and should not have modified the file' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo=blah\nfoo2\nfoo=baz")
+ end
+ @provider.exists?.should be_nil
+ expect { @provider.create }.to raise_error(Puppet::Error, /More than one line.*matches/)
+ File.read(@tmpfile).should eql("foo1\nfoo=blah\nfoo2\nfoo=baz")
+ end
+
+ it 'should replace a line that matches' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo=blah\nfoo2")
+ end
+ @provider.exists?.should be_nil
+ @provider.create
+ File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2")
+ end
+ it 'should add a new line if no lines match' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo2")
+ end
+ @provider.exists?.should be_nil
+ @provider.create
+ File.read(@tmpfile).should eql("foo1\nfoo2\nfoo = bar\n")
+ end
+ it 'should do nothing if the exact line already exists' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo = bar\nfoo2")
+ end
+ @provider.exists?.should be_true
+ @provider.create
+ File.read(@tmpfile).chomp.should eql("foo1\nfoo = bar\nfoo2")
end
- @provider.exists?.should be_nil
end
- it 'should append to an existing file when creating' do
- @provider.create
- File.read(@tmpfile).chomp.should == 'foo'
+
+ context "when removing" do
+ before :each do
+ # TODO: these should be ported over to use the PuppetLabs spec_helper
+ # file fixtures once the following pull request has been merged:
+ # https://github.com/puppetlabs/puppetlabs-stdlib/pull/73/files
+ tmp = Tempfile.new('tmp')
+ @tmpfile = tmp.path
+ tmp.close!
+ @resource = Puppet::Type::File_line.new(
+ {:name => 'foo', :path => @tmpfile, :line => 'foo', :ensure => 'absent' }
+ )
+ @provider = provider_class.new(@resource)
+ end
+ it 'should remove the line if it exists' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo\nfoo2")
+ end
+ @provider.destroy
+ File.read(@tmpfile).should eql("foo1\nfoo2")
+ end
+
+ it 'should remove the line without touching the last new line' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo\nfoo2\n")
+ end
+ @provider.destroy
+ File.read(@tmpfile).should eql("foo1\nfoo2\n")
+ end
+
+ it 'should remove any occurence of the line' do
+ File.open(@tmpfile, 'w') do |fh|
+ fh.write("foo1\nfoo\nfoo2\nfoo\nfoo")
+ end
+ @provider.destroy
+ File.read(@tmpfile).should eql("foo1\nfoo2\n")
+ end
end
end
diff --git a/spec/unit/puppet/type/file_line_spec.rb b/spec/unit/puppet/type/file_line_spec.rb
index 7e07c06..edc64bd 100644
--- a/spec/unit/puppet/type/file_line_spec.rb
+++ b/spec/unit/puppet/type/file_line_spec.rb
@@ -1,24 +1,69 @@
require 'puppet'
require 'tempfile'
describe Puppet::Type.type(:file_line) do
- before :each do
- @file_line = Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'line', :path => '/tmp/path')
+ let :file_line do
+ Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'line', :path => '/tmp/path')
end
it 'should accept a line and path' do
- @file_line[:line] = 'my_line'
- @file_line[:line].should == 'my_line'
+ file_line[:line] = 'my_line'
+ file_line[:line].should == 'my_line'
+ file_line[:path] = '/my/path'
+ file_line[:path].should == '/my/path'
+ end
+ it 'should accept a match regex' do
+ file_line[:match] = '^foo.*$'
+ file_line[:match].should == '^foo.*$'
+ end
+ it 'should not accept a match regex that does not match the specified line' do
+ expect {
+ Puppet::Type.type(:file_line).new(
+ :name => 'foo',
+ :path => '/my/path',
+ :line => 'foo=bar',
+ :match => '^bar=blah$'
+ )}.to raise_error(Puppet::Error, /the value must be a regex that matches/)
+ end
+ it 'should accept a match regex that does match the specified line' do
+ expect {
+ Puppet::Type.type(:file_line).new(
+ :name => 'foo',
+ :path => '/my/path',
+ :line => 'foo=bar',
+ :match => '^\s*foo=.*$'
+ )}.not_to raise_error
end
it 'should accept posix filenames' do
- @file_line[:path] = '/tmp/path'
- @file_line[:path].should == '/tmp/path'
+ file_line[:path] = '/tmp/path'
+ file_line[:path].should == '/tmp/path'
end
it 'should not accept unqualified path' do
- expect { @file_line[:path] = 'file' }.should raise_error(Puppet::Error, /File paths must be fully qualified/)
+ expect { file_line[:path] = 'file' }.to raise_error(Puppet::Error, /File paths must be fully qualified/)
end
it 'should require that a line is specified' do
- expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.should raise_error(Puppet::Error, /Both line and path are required attributes/)
+ expect { Puppet::Type.type(:file_line).new(:name => 'foo', :path => '/tmp/file') }.to raise_error(Puppet::Error, /Both line and path are required attributes/)
end
it 'should require that a file is specified' do
- expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.should raise_error(Puppet::Error, /Both line and path are required attributes/)
+ expect { Puppet::Type.type(:file_line).new(:name => 'foo', :line => 'path') }.to raise_error(Puppet::Error, /Both line and path are required attributes/)
+ end
+ it 'should default to ensure => present' do
+ file_line[:ensure].should eq :present
+ end
+
+ it "should autorequire the file it manages" do
+ catalog = Puppet::Resource::Catalog.new
+ file = Puppet::Type.type(:file).new(:name => "/tmp/path")
+ catalog.add_resource file
+ catalog.add_resource file_line
+
+ relationship = file_line.autorequire.find do |rel|
+ (rel.source.to_s == "File[/tmp/path]") and (rel.target.to_s == file_line.to_s)
+ end
+ relationship.should be_a Puppet::Relationship
+ end
+
+ it "should not autorequire the file it manages if it is not managed" do
+ catalog = Puppet::Resource::Catalog.new
+ catalog.add_resource file_line
+ file_line.autorequire.should be_empty
end
end
diff --git a/tests/has_interface_with.pp b/tests/has_interface_with.pp
new file mode 100644
index 0000000..e1f1353
--- /dev/null
+++ b/tests/has_interface_with.pp
@@ -0,0 +1,10 @@
+include stdlib
+info('has_interface_with(\'lo\'):', has_interface_with('lo'))
+info('has_interface_with(\'loX\'):', has_interface_with('loX'))
+info('has_interface_with(\'ipaddress\', \'127.0.0.1\'):', has_interface_with('ipaddress', '127.0.0.1'))
+info('has_interface_with(\'ipaddress\', \'127.0.0.100\'):', has_interface_with('ipaddress', '127.0.0.100'))
+info('has_interface_with(\'network\', \'127.0.0.0\'):', has_interface_with('network', '127.0.0.0'))
+info('has_interface_with(\'network\', \'128.0.0.0\'):', has_interface_with('network', '128.0.0.0'))
+info('has_interface_with(\'netmask\', \'255.0.0.0\'):', has_interface_with('netmask', '255.0.0.0'))
+info('has_interface_with(\'netmask\', \'256.0.0.0\'):', has_interface_with('netmask', '256.0.0.0'))
+
diff --git a/tests/has_ip_address.pp b/tests/has_ip_address.pp
new file mode 100644
index 0000000..8429a88
--- /dev/null
+++ b/tests/has_ip_address.pp
@@ -0,0 +1,3 @@
+include stdlib
+info('has_ip_address(\'192.168.1.256\'):', has_ip_address('192.168.1.256'))
+info('has_ip_address(\'127.0.0.1\'):', has_ip_address('127.0.0.1'))
diff --git a/tests/has_ip_network.pp b/tests/has_ip_network.pp
new file mode 100644
index 0000000..a15d8c0
--- /dev/null
+++ b/tests/has_ip_network.pp
@@ -0,0 +1,4 @@
+include stdlib
+info('has_ip_network(\'127.0.0.0\'):', has_ip_network('127.0.0.0'))
+info('has_ip_network(\'128.0.0.0\'):', has_ip_network('128.0.0.0'))
+