Module: RSpec::Puppet::Support

Included in:
ClassExampleGroup, DefineExampleGroup, FunctionExampleGroup, HostExampleGroup, TypeExampleGroup
Defined in:
lib/rspec-puppet/support.rb

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:



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

def adapter
  @adapter
end

Instance Method Details

#build_catalog(*args) ⇒ Object



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

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



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/rspec-puppet/support.rb', line 150

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



91
92
93
# File 'lib/rspec-puppet/support.rb', line 91

def class_name
  self.class.top_level_description.downcase
end

#environmentObject



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

def environment
  'rp_env'
end

#escape_special_chars(string) ⇒ Object



196
197
198
199
# File 'lib/rspec-puppet/support.rb', line 196

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

#facts_hash(node) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
# File 'lib/rspec-puppet/support.rb', line 107

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



17
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 17

def load_catalogue(type, exported = false)
  vardir = setup_puppet

  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)

  FileUtils.rm_rf(vardir) if File.directory?(vardir)
  catalogue
end

#munge_facts(facts) ⇒ Object

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



184
185
186
187
188
189
190
191
192
193
194
# File 'lib/rspec-puppet/support.rb', line 184

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



82
83
84
85
86
87
88
89
# File 'lib/rspec-puppet/support.rb', line 82

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

#param_strObject



125
126
127
128
129
130
131
132
133
134
135
# File 'lib/rspec-puppet/support.rb', line 125

def param_str
  params.keys.map do |r|
    param_val = params[r]
    param_val_str = if param_val == :undef
                      'undef'  # verbatim undef keyword
                    else
                      escape_special_chars(param_val.inspect)
                    end
    "#{r.to_s} => #{param_val_str}"
  end.join(', ')
end

#pre_condObject



95
96
97
98
99
100
101
102
103
104
105
# File 'lib/rspec-puppet/support.rb', line 95

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

#rspec_compatibilityObject



201
202
203
204
205
206
207
# File 'lib/rspec-puppet/support.rb', line 201

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



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

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

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

  vardir
end

#stub_facts!(facts) ⇒ Object



172
173
174
# File 'lib/rspec-puppet/support.rb', line 172

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

#subjectObject



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

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
# 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 == :define
    if self.respond_to? :params
      "#{class_name} { '#{title}': #{param_str} }"
    else
      "#{class_name} { '#{title}': }"
    end
  elsif type == :host
    nil
  end
end