Class: Onceover::TestConfig

Inherits:
Object
  • Object
show all
Defined in:
lib/onceover/testconfig.rb

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(file, opts = {}) ⇒ TestConfig

Returns a new instance of TestConfig.



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/onceover/testconfig.rb', line 33

def initialize(file, opts = {})
  begin
    config = YAML.safe_load(File.read(file), [Symbol])
  rescue Errno::ENOENT
    raise "Could not find #{file}"
  rescue Psych::SyntaxError
    raise "Could not parse #{file}, check that it is valid YAML and that the encoding is correct"
  end

  @classes           = []
  @nodes             = []
  @node_groups       = []
  @class_groups      = []
  @spec_tests        = []
  @acceptance_tests  = []
  @opts              = opts
  @mock_functions    = config['functions']
  @before_conditions = config['before'] || []
  @after_conditions  = config['after']
  @strict_variables  = opts[:strict_variables] ? 'yes' : 'no'
  @included_specs    = [config['include_spec_files'] || ['**/*']].flatten
  
  # Set dynamic defaults for format
  if Array(opts[:format]) == [:defaults]
    @formatters = opts[:parallel] ? ['OnceoverFormatterParallel'] : ['OnceoverFormatter']
  else
    @formatters = Array(opts[:format])
  end

  # Initialise all of the classes and nodes
  config['classes'].each { |clarse| Onceover::Class.new(clarse) } unless config['classes'] == nil
  @classes = Onceover::Class.all

  config['nodes'].each { |node| Onceover::Node.new(node) } unless config['nodes'] == nil
  @nodes = Onceover::Node.all

  # Add the 'all_classes' and 'all_nodes' default groups
  @node_groups  << Onceover::Group.new('all_nodes', @nodes)
  @class_groups << Onceover::Group.new('all_classes', @classes)

  # Initialise all of the groups
  config['node_groups'].each { |name, members| @node_groups << Onceover::Group.new(name, members) } unless config['node_groups'] == nil
  config['class_groups'].each { |name, members| @class_groups << Onceover::Group.new(name, members) } unless config['class_groups'] == nil

  @filter_tags    = opts[:tags]      ? [opts[:tags].split(',')].flatten : nil
  @filter_classes = opts[:classes]   ? [opts[:classes].split(',')].flatten.map {|x| Onceover::Class.find(x)} : nil
  @filter_nodes   = opts[:nodes]     ? [opts[:nodes].split(',')].flatten.map {|x| Onceover::Node.find(x)} : nil
  @skip_r10k      = opts[:skip_r10k] ? true : false
  @force          = opts[:force] || false

  # Validate the mock_functions
  if @mock_functions && @mock_functions.any? { |name, details| details.has_key? 'type' }
    logger.warn "The 'type' key for mocked functions is deprecated and will be ignored, please remove it."
  end

  # Loop over all of the items in the test matrix and add those as test
  # objects to the list of tests
  config['test_matrix'].each do |test_hash|
    test_hash.each do |machines, settings|
      if settings['tests'] == 'spec'
        @spec_tests << Onceover::Test.new(machines, settings['classes'], settings)
      elsif settings['tests'] == 'acceptance'
        @acceptance_tests << Onceover::Test.new(machines, settings['classes'], settings)
      elsif settings['tests'] == 'all_tests'
        tst = Onceover::Test.new(machines,settings['classes'],settings)
        @spec_tests << tst
        @acceptance_tests << tst
      end
    end
  end
end

Instance Attribute Details

#acceptance_testsObject

Returns the value of attribute acceptance_tests.



19
20
21
# File 'lib/onceover/testconfig.rb', line 19

def acceptance_tests
  @acceptance_tests
end

#after_conditionsObject

Returns the value of attribute after_conditions.



27
28
29
# File 'lib/onceover/testconfig.rb', line 27

def after_conditions
  @after_conditions
end

#before_conditionsObject

Returns the value of attribute before_conditions.



26
27
28
# File 'lib/onceover/testconfig.rb', line 26

def before_conditions
  @before_conditions
end

#class_groupsObject

Returns the value of attribute class_groups.



17
18
19
# File 'lib/onceover/testconfig.rb', line 17

def class_groups
  @class_groups
end

#classesObject

Returns the value of attribute classes.



14
15
16
# File 'lib/onceover/testconfig.rb', line 14

def classes
  @classes
end

#environmentObject

Returns the value of attribute environment.



20
21
22
# File 'lib/onceover/testconfig.rb', line 20

def environment
  @environment
end

#filter_classesObject

Returns the value of attribute filter_classes.



23
24
25
# File 'lib/onceover/testconfig.rb', line 23

def filter_classes
  @filter_classes
end

#filter_nodesObject

Returns the value of attribute filter_nodes.



24
25
26
# File 'lib/onceover/testconfig.rb', line 24

def filter_nodes
  @filter_nodes
end

#filter_tagsObject

Returns the value of attribute filter_tags.



22
23
24
# File 'lib/onceover/testconfig.rb', line 22

def filter_tags
  @filter_tags
end

#forceObject

Returns the value of attribute force.



29
30
31
# File 'lib/onceover/testconfig.rb', line 29

def force
  @force
end

#formattersObject

Returns the value of attribute formatters.



31
32
33
# File 'lib/onceover/testconfig.rb', line 31

def formatters
  @formatters
end

#mock_functionsObject

Returns the value of attribute mock_functions.



25
26
27
# File 'lib/onceover/testconfig.rb', line 25

def mock_functions
  @mock_functions
end

#node_groupsObject

Returns the value of attribute node_groups.



16
17
18
# File 'lib/onceover/testconfig.rb', line 16

def node_groups
  @node_groups
end

#nodesObject

Returns the value of attribute nodes.



15
16
17
# File 'lib/onceover/testconfig.rb', line 15

def nodes
  @nodes
end

#optsObject

Returns the value of attribute opts.



21
22
23
# File 'lib/onceover/testconfig.rb', line 21

def opts
  @opts
end

#skip_r10kObject

Returns the value of attribute skip_r10k.



28
29
30
# File 'lib/onceover/testconfig.rb', line 28

def skip_r10k
  @skip_r10k
end

#spec_testsObject

Returns the value of attribute spec_tests.



18
19
20
# File 'lib/onceover/testconfig.rb', line 18

def spec_tests
  @spec_tests
end

#strict_variablesObject

Returns the value of attribute strict_variables.



30
31
32
# File 'lib/onceover/testconfig.rb', line 30

def strict_variables
  @strict_variables
end

Class Method Details

.find_list(thing) ⇒ Object



116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/onceover/testconfig.rb', line 116

def self.find_list(thing)
  # Takes a string and finds an object or list of objects to match, will
  # take nodes, classes or groups

  # We want to supress warnings for this bit
  old_level = logger.level
  logger.level = :error
  if Onceover::Group.find(thing)
    logger.level = old_level
    return Onceover::Group.find(thing).members
  elsif Onceover::Class.find(thing)
    logger.level = old_level
    return [Onceover::Class.find(thing)]
  elsif Onceover::Node.find(thing)
    logger.level = old_level
    return [Onceover::Node.find(thing)]
  else
    logger.level = old_level
    raise "Could not find #{thing} in list of classes, nodes or groups"
  end
end

.subtractive_to_list(subtractive_hash) ⇒ Object



138
139
140
141
142
143
144
145
146
147
148
149
150
# File 'lib/onceover/testconfig.rb', line 138

def self.subtractive_to_list(subtractive_hash)
  # Take a hash that looks like this:
  # { 'include' => 'somegroup'
  #   'exclude' => 'other'}
  # and return a list of classes/nodes
  if subtractive_hash.has_key?('include') && subtractive_hash.has_key?('exclude')
    include_list = Onceover::TestConfig.find_list(subtractive_hash['include']).flatten
    exclude_list = Onceover::TestConfig.find_list(subtractive_hash['exclude']).flatten
    include_list - exclude_list
  else
    raise "The classes/nodes hash must have an `exclude` if using an `include`"
  end
end

Instance Method Details

#copy_spec_files(repo) ⇒ Object



240
241
242
243
244
245
246
247
248
249
250
251
# File 'lib/onceover/testconfig.rb', line 240

def copy_spec_files(repo)
  source_files = @included_specs.map { |glob| Dir.glob "#{repo.spec_dir}/#{glob}" }.flatten.uniq
  source_files.each do |source_file|
    target_file = File.join(repo.tempdir, 'spec', source_file.sub(/^#{repo.spec_dir}/, ''))
    if File.directory?(source_file)
      FileUtils.cp_r source_file, target_file unless File.exists? target_file
    else
      FileUtils.mkdir_p File.dirname target_file
      FileUtils.cp source_file, target_file
    end
  end
end


253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/onceover/testconfig.rb', line 253

def create_fixtures_symlinks(repo)
  logger.debug "Creating fixtures symlinks"
  FileUtils.rm_rf("#{repo.tempdir}/spec/fixtures/modules")
  FileUtils.mkdir_p("#{repo.tempdir}/spec/fixtures/modules")
  repo.temp_modulepath.split(':').each do |path|
    Dir["#{path}/*"].each do |mod|
      modulename = File.basename(mod)
      link = "#{repo.tempdir}/spec/fixtures/modules/#{modulename}"
      logger.debug "Symlinking #{mod} to #{link}"
      unless File.symlink?(link)
        # Ruby only sets File::ALT_SEPARATOR on Windows and Rubys standard library
        # uses this to check for Windows
        if !!File::ALT_SEPARATOR
          mod = File.join(File.dirname(link), mod) unless Pathname.new(mod).absolute?
          if Dir.respond_to?(:create_junction)
            Dir.create_junction(link, mod)
          else
            system("call mklink /J \"#{link.gsub('/', '\\')}\" \"#{mod.gsub('/', '\\')}\"")
          end
        else
          FileUtils.ln_s(mod, link)
        end
      end
    end
  end
end

#filter_test(test, method, filter) ⇒ Object



300
301
302
303
304
305
306
307
308
309
310
311
# File 'lib/onceover/testconfig.rb', line 300

def filter_test(test, method, filter)
  if test.send(method)
    if method == 'tags' && filter.start_with?('~')
      filter = filter.sub(/^~/, '')
      ! test.send(method).include?(filter)
    else
      test.send(method).include?(filter)
    end
  else
    false
  end
end

#pre_conditionObject



172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/onceover/testconfig.rb', line 172

def pre_condition
  # Read all the pre_conditions and return the string
  spec_dir = Onceover::Controlrepo.new(@opts).spec_dir
  puppetcode = []
  Dir["#{spec_dir}/pre_conditions/*.pp"].each do |condition_file|
    logger.debug "Reading pre_conditions from #{condition_file}"
    puppetcode << File.read(condition_file)
  end
  return nil if puppetcode.count.zero?

  puppetcode.join("\n")
end

#run_filters(tests) ⇒ Object



280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
# File 'lib/onceover/testconfig.rb', line 280

def run_filters(tests)
  # All of this needs to be applied AFTER deduplication but BEFORE writing
  filters = {
    'tags'    => @filter_tags,
    'classes' => @filter_classes,
    'nodes'   => @filter_nodes
  }
  filters.each do |method, filter_list|
    if filter_list
      # Remove tests that do not have matching tags
      tests.keep_if do |test|
        filter_list.any? do |filter|
          filter_test test, method, filter
        end
      end
    end
  end
  tests
end

#to_sObject



105
106
107
108
109
110
111
112
113
114
# File 'lib/onceover/testconfig.rb', line 105

def to_s
  require 'colored'

  <<-TESTCONF.gsub(/^\s{4}/,'')
  #{'classes'.green}      #{@classes.map{|c|c.name}}
  #{'nodes'.green}        #{@nodes.map{|n|n.name}}
  #{'class_groups'.green} #{@class_groups}
  #{'node_groups'.green}  #{@node_groups.map{|g|g.name}}
  TESTCONF
end

#verify_acceptance_test(controlrepo, test) ⇒ Object



160
161
162
163
164
165
166
167
168
169
170
# File 'lib/onceover/testconfig.rb', line 160

def verify_acceptance_test(controlrepo, test)
  warn "[DEPRECATION] #{__method__} is deprecated due to the removal of Beaker"

  require 'yaml'
  nodeset = YAML.load_file(controlrepo.nodeset_file)
  test.nodes.each do |node|
    unless nodeset['HOSTS'].has_key?(node.name)
      raise "Could not find nodeset for node: #{node.name}"
    end
  end
end

#verify_spec_test(controlrepo, test) ⇒ Object



152
153
154
155
156
157
158
# File 'lib/onceover/testconfig.rb', line 152

def verify_spec_test(controlrepo, test)
  test.nodes.each do |node|
    unless controlrepo.facts_files.any? { |file| file =~ /\/#{node.name}\.json/ }
      raise "Could not find factset for node: #{node.name}"
    end
  end
end

#write_acceptance_tests(location, tests) ⇒ Object



193
194
195
196
197
198
199
# File 'lib/onceover/testconfig.rb', line 193

def write_acceptance_tests(location, tests)
  warn "[DEPRECATION] #{__method__} is deprecated due to the removal of Beaker"

  File.write(
    "#{location}/acceptance_spec.rb",
    Onceover::Controlrepo.evaluate_template('acceptance_test_spec.rb.erb', binding))
end

#write_rakefile(location, pattern) ⇒ Object



208
209
210
211
212
213
# File 'lib/onceover/testconfig.rb', line 208

def write_rakefile(location, pattern)
  File.write(
    "#{location}/Rakefile",
    Onceover::Controlrepo.evaluate_template('testconfig_Rakefile.erb', binding)
  )
end

#write_spec_helper(location, repo) ⇒ Object



215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/onceover/testconfig.rb', line 215

def write_spec_helper(location, repo)
  environmentpath = "#{repo.tempdir}/#{repo.environmentpath}"
  modulepath = repo.config['modulepath']
  modulepath.delete("$basemodulepath")
  modulepath.map! do |path|
    "#{environmentpath}/production/#{path}"
  end

  # We need to select the right delimiter based on OS
  require 'facter'
  if Facter[:kernel].value == 'windows'
    modulepath = modulepath.join(";")
  else
    modulepath = modulepath.join(':')
  end

  repo.temp_modulepath = modulepath

  # Use an ERB template to write a spec test
  File.write(
    "#{location}/spec_helper.rb",
    Onceover::Controlrepo.evaluate_template('spec_helper.rb.erb', binding)
  )
end

#write_spec_helper_acceptance(location, repo) ⇒ Object



201
202
203
204
205
206
# File 'lib/onceover/testconfig.rb', line 201

def write_spec_helper_acceptance(location, repo)
  File.write(
    "#{location}/spec_helper_acceptance.rb",
    Onceover::Controlrepo.evaluate_template('spec_helper_acceptance.rb.erb', binding)
  )
end

#write_spec_test(location, test) ⇒ Object



185
186
187
188
189
190
191
# File 'lib/onceover/testconfig.rb', line 185

def write_spec_test(location, test)
  # Use an ERB template to write a spec test
  File.write(
    "#{location}/#{test.to_s}_spec.rb",
    Onceover::Controlrepo.evaluate_template('test_spec.rb.erb', binding)
  )
end