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.



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
104
105
# File 'lib/onceover/testconfig.rb', line 34

def initialize(file, opts = {})
  begin
    config = YAML.safe_load(File.read(file), permitted_classes: [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
  @fail_fast      = opts[:fail_fast] || 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

#fail_fastObject

Returns the value of attribute fail_fast.



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

def fail_fast
  @fail_fast
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.



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

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.



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

def strict_variables
  @strict_variables
end

Class Method Details

.find_list(thing) ⇒ Object



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

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



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

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



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

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.exist? target_file
    else
      FileUtils.mkdir_p File.dirname target_file
      FileUtils.cp source_file, target_file
    end
  end
end


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

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



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

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



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

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



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

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



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

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



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

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



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

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



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

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



210
211
212
213
214
215
# File 'lib/onceover/testconfig.rb', line 210

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

#write_spec_helper(location, repo) ⇒ Object



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

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



203
204
205
206
207
208
# File 'lib/onceover/testconfig.rb', line 203

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



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

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