Module: RSpec::Puppet::Support

Constant Summary collapse

@@cache =
RSpec::Puppet::Cache.new

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#adapterClass < RSpec::Puppet::Adapters::Base]

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Returns Class < RSpec::Puppet::Adapters::Base].

Returns:



256
257
258
# File 'lib/rspec-puppet/support.rb', line 256

def adapter
  @adapter
end

Instance Method Details

#build_catalog(*args) ⇒ Object



210
211
212
213
214
# File 'lib/rspec-puppet/support.rb', line 210

def build_catalog(*args)
  @@cache.get(*args) do |*args|
    build_catalog_without_cache(*args)
  end
end

#build_catalog_without_cache(nodename, facts_val, hiera_config_val, code, exported) ⇒ Object



184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
# File 'lib/rspec-puppet/support.rb', line 184

def build_catalog_without_cache(nodename, facts_val, hiera_config_val, code, exported)

  # If we're going to rebuild the catalog, we should clear the cached instance
  # of Hiera that Puppet is using.  This opens the possibility of the catalog
  # now being rebuilt against a differently configured Hiera (i.e. :hiera_config
  # set differently in one example group vs. another).
  # It would be nice if Puppet offered a public API for invalidating their
  # cached instance of Hiera, but que sera sera.  We will go directly against
  # the implementation out of absolute necessity.
  HieraPuppet.instance_variable_set('@hiera', nil) if defined? HieraPuppet

  Puppet[:code] = code

  stub_facts! facts_val

  node_facts = Puppet::Node::Facts.new(nodename, facts_val.dup)

  node_obj = Puppet::Node.new(nodename, { :parameters => facts_val, :facts => node_facts })

  adapter.catalog(node_obj, exported)
end

#class_nameObject



97
98
99
# File 'lib/rspec-puppet/support.rb', line 97

def class_name
  self.class.top_level_description.downcase
end

#environmentObject



14
15
16
# File 'lib/rspec-puppet/support.rb', line 14

def environment
  'rp_env'
end

#escape_special_chars(string) ⇒ Object



230
231
232
233
# File 'lib/rspec-puppet/support.rb', line 230

def escape_special_chars(string)
  string.gsub!(/\$/, "\\$")
  string
end

#facts_hash(node) ⇒ Object



113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# File 'lib/rspec-puppet/support.rb', line 113

def facts_hash(node)
  facts_val = {
    'clientversion' => Puppet::PUPPETVERSION,
    'environment'   => environment,
    'hostname'      => node.split('.').first,
    'fqdn'          => node,
    'domain'        => node.split('.', 2).last,
    'clientcert'    => node
  }

  if RSpec.configuration.default_facts.any?
    facts_val.merge!(munge_facts(RSpec.configuration.default_facts))
  end

  facts_val.merge!(munge_facts(facts)) if self.respond_to?(:facts)
  facts_val
end

#import_strObject



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rspec-puppet/support.rb', line 40

def import_str
  import_str = ""
  adapter.modulepath.each { |d|
    if File.exists?(File.join(d, 'manifests', 'init.pp'))
      path_to_manifest = File.join([
        d,
        'manifests',
        class_name.split('::')[1..-1]
      ].flatten)
      import_str = [
        "import '#{d}/manifests/init.pp'",
        "import '#{path_to_manifest}.pp'",
        '',
      ].join("\n")
      break
    elsif File.exists?(d)
      import_str = "import '#{adapter.manifest}'\n"
      break
    end
  }

  import_str
end

#load_catalogue(type, exported = false) ⇒ Object



18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/rspec-puppet/support.rb', line 18

def load_catalogue(type, exported = false)
  with_vardir do
    if Puppet.version.to_f >= 4.0 or Puppet[:parser] == 'future'
      code = [pre_cond, test_manifest(type)].compact.join("\n")
    else
      code = [import_str, pre_cond, test_manifest(type)].compact.join("\n")
    end

    node_name = nodename(type)

    hiera_config_value = self.respond_to?(:hiera_config) ? hiera_config : nil

    catalogue = build_catalog(node_name, facts_hash(node_name), hiera_config_value, code, exported)

    test_module = class_name.split('::').first
    RSpec::Puppet::Coverage.add_filter(type.to_s, self.class.description)
    RSpec::Puppet::Coverage.add_from_catalog(catalogue, test_module)

    catalogue
  end
end

#munge_facts(facts) ⇒ Object

Facter currently supports lower case facts. Bug FACT-777 has been submitted to support case sensitive facts.



218
219
220
221
222
223
224
225
226
227
228
# File 'lib/rspec-puppet/support.rb', line 218

def munge_facts(facts)
  return facts.reduce({}) do | memo, (k, v)|
    memo.tap { |m| m[k.to_s.downcase] = munge_facts(v) }
  end if facts.is_a? Hash

  return facts.reduce([]) do |memo, v|
    memo << munge_facts(v); memo
  end if facts.is_a? Array

  facts
end

#nodename(type) ⇒ Object



88
89
90
91
92
93
94
95
# File 'lib/rspec-puppet/support.rb', line 88

def nodename(type)
  return node if self.respond_to?(:node)
  if [:class, :define, :function, :application].include? type
    Puppet[:certname]
  else
    class_name
  end
end

#param_strObject



131
132
133
# File 'lib/rspec-puppet/support.rb', line 131

def param_str
  param_str_from_hash(params)
end

#param_str_from_hash(params_hash) ⇒ Object



149
150
151
152
153
154
155
# File 'lib/rspec-puppet/support.rb', line 149

def param_str_from_hash(params_hash)
  # the param_str has special quoting rules, because the top-level keys are the Puppet
  # params, which may not be quoted
  params_hash.collect do |k,v|
    "#{k.to_s} => #{str_from_value(v)}"
  end.join(', ')
end

#pre_condObject



101
102
103
104
105
106
107
108
109
110
111
# File 'lib/rspec-puppet/support.rb', line 101

def pre_cond
  if self.respond_to?(:pre_condition) && !pre_condition.nil?
    if pre_condition.is_a? Array
      pre_condition.compact.join("\n")
    else
      pre_condition
    end
  else
    nil
  end
end

#ref(type, title) ⇒ RSpec::Puppet::RawString

Helper to return a resource/node reference, so it gets translated in params to a raw string without quotes.

Parameters:

  • type (String)

    reference type

  • title (String)

    reference title

Returns:



249
250
251
# File 'lib/rspec-puppet/support.rb', line 249

def ref(type, title)
  return RSpec::Puppet::RawString.new("#{type}['#{title}']")
end

#rspec_compatibilityObject



235
236
237
238
239
240
241
# File 'lib/rspec-puppet/support.rb', line 235

def rspec_compatibility
  if RSpec::Version::STRING < '3'
    # RSpec 2 compatibility:
    alias_method :failure_message_for_should, :failure_message
    alias_method :failure_message_for_should_not, :failure_message_when_negated
  end
end

#setup_puppetObject



157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/rspec-puppet/support.rb', line 157

def setup_puppet
  vardir = Dir.mktmpdir
  Puppet[:vardir] = vardir

  # Enable app_management by default for Puppet versions that support it
  if Puppet.version.to_f >= 4.3
    Puppet[:app_management] = true
  end

  adapter.modulepath.map do |d|
    Dir["#{d}/*/lib"].entries
  end.flatten.each do |lib|
    $LOAD_PATH << lib
  end

  vardir
end

#str_from_value(value) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/rspec-puppet/support.rb', line 135

def str_from_value(value)
  case value
  when Hash
    kvs = value.collect do |k,v|
      "#{str_from_value(k)} => #{str_from_value(v)}"
    end.join(", ")
    "{ #{kvs} }"
  when :undef
    'undef'  # verbatim undef keyword
  else
    escape_special_chars(value.inspect)
  end
end

#stub_facts!(facts) ⇒ Object



206
207
208
# File 'lib/rspec-puppet/support.rb', line 206

def stub_facts!(facts)
  facts.each { |k, v| Facter.add(k) { setcode { v } } }
end

#subjectObject



10
11
12
# File 'lib/rspec-puppet/support.rb', line 10

def subject
  lambda { catalogue }
end

#test_manifest(type) ⇒ Object



64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/rspec-puppet/support.rb', line 64

def test_manifest(type)
  if type == :class
    if !self.respond_to?(:params) || params == {}
      "include #{class_name}"
    else
      "class { '#{class_name}': #{param_str} }"
    end
  elsif type == :application
    if self.respond_to? :params
      "site { #{class_name} { '#{title}': #{param_str} } }"
    else
      raise ArgumentException, "You need to provide params for an application"
    end
  elsif type == :define
    if self.respond_to? :params
      "#{class_name} { '#{title}': #{param_str} }"
    else
      "#{class_name} { '#{title}': }"
    end
  elsif type == :host
    nil
  end
end

#with_vardirObject



175
176
177
178
179
180
181
182
# File 'lib/rspec-puppet/support.rb', line 175

def with_vardir
  begin
    vardir = setup_puppet
    return yield(vardir) if block_given?
  ensure
    FileUtils.rm_rf(vardir) if File.directory?(vardir)
  end
end