Class: RSpec::Puppet::Coverage

Inherits:
Object
  • Object
show all
Extended by:
Forwardable
Defined in:
lib/rspec-puppet/coverage.rb

Defined Under Namespace

Classes: ResourceWrapper

Class Attribute Summary collapse

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeCoverage

Returns a new instance of Coverage.



35
36
37
38
# File 'lib/rspec-puppet/coverage.rb', line 35

def initialize
  @collection = {}
  @filters = ['Stage[main]', 'Class[Settings]', 'Class[main]', 'Node[default]']
end

Class Attribute Details

.instanceObject



30
31
32
# File 'lib/rspec-puppet/coverage.rb', line 30

def instance
  @instance ||= new
end

Instance Attribute Details

#filtersObject

Returns the value of attribute filters.



20
21
22
# File 'lib/rspec-puppet/coverage.rb', line 20

def filters
  @filters
end

Instance Method Details

#add(resource) ⇒ Object



63
64
65
66
67
# File 'lib/rspec-puppet/coverage.rb', line 63

def add(resource)
  if !exists?(resource) && !filtered?(resource)
    @collection[resource.to_s] = ResourceWrapper.new(resource)
  end
end

#add_filter(type, title) ⇒ Object



69
70
71
72
73
74
75
76
77
78
79
80
# File 'lib/rspec-puppet/coverage.rb', line 69

def add_filter(type, title)
  def capitalize_name(name)
    name.split('::').map { |subtitle| subtitle.capitalize }.join('::')
  end

  type = capitalize_name(type)
  if type == 'Class'
    title = capitalize_name(title)
  end

  @filters << "#{type}[#{title}]"
end

#add_from_catalog(catalog, test_module) ⇒ Object

add all resources from catalog declared in module test_module



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

def add_from_catalog(catalog, test_module)
  coverable_resources = catalog.to_a.reject { |resource| !test_module.nil? && filter_resource?(resource, test_module) }
  coverable_resources.each do |resource|
    add(resource)
  end
end

#capitalize_name(name) ⇒ Object



70
71
72
# File 'lib/rspec-puppet/coverage.rb', line 70

def capitalize_name(name)
  name.split('::').map { |subtitle| subtitle.capitalize }.join('::')
end

#cover!(resource) ⇒ Object



94
95
96
97
98
# File 'lib/rspec-puppet/coverage.rb', line 94

def cover!(resource)
  if !filtered?(resource) && (wrapper = find(resource))
    wrapper.touch!
  end
end

#coverage_test(coverage_desired, report) ⇒ Object



129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/rspec-puppet/coverage.rb', line 129

def coverage_test(coverage_desired, report)
  coverage_actual = report[:coverage]
  coverage_desired ||= 0

  if coverage_desired.is_a?(Numeric) && coverage_desired.to_f <= 100.00 && coverage_desired.to_f >= 0.0
    coverage_test = RSpec.describe("Code coverage")
    coverage_results = coverage_test.example("must cover at least #{coverage_desired}% of resources") do
      expect( coverage_actual.to_f ).to be >= coverage_desired.to_f
    end
    coverage_test.run(RSpec.configuration.reporter)

    # This is not available on RSpec 2.x
    if coverage_results.execution_result.respond_to?(:pending_message)
      coverage_results.execution_result.pending_message = report[:text]
    end
  else
    puts "The desired coverage must be 0 <= x <= 100, not '#{coverage_desired.inspect}'"
  end
end

#filtered?(resource) ⇒ Boolean

Returns:

  • (Boolean)


90
91
92
# File 'lib/rspec-puppet/coverage.rb', line 90

def filtered?(resource)
  filters.include?(resource.to_s)
end

#load_results(path) ⇒ Object



55
56
57
58
59
60
61
# File 'lib/rspec-puppet/coverage.rb', line 55

def load_results(path)
  saved_results = JSON.parse(File.read(path))
  saved_results.each do |resource, data|
    add(resource)
    cover!(resource) if data['touched']
  end
end

#merge_resultsObject



47
48
49
50
51
52
53
# File 'lib/rspec-puppet/coverage.rb', line 47

def merge_results
  pattern = File.join(Dir.tmpdir, "rspec-puppet-coverage-#{Digest::MD5.hexdigest(Dir.pwd)}-*")
  Dir[pattern].each do |result_file|
    load_results(result_file)
    FileUtils.rm(result_file)
  end
end

#parallel_tests?Boolean

Returns:

  • (Boolean)


115
116
117
# File 'lib/rspec-puppet/coverage.rb', line 115

def parallel_tests?
  !!ENV['TEST_ENV_NUMBER']
end

#report!(coverage_desired = nil) ⇒ Object



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

def report!(coverage_desired = nil)
  if parallel_tests?
    require 'parallel_tests'

    if ParallelTests.first_process?
      ParallelTests.wait_for_other_processes_to_finish
      run_report(coverage_desired)
    else
      save_results
    end
  else
    run_report(coverage_desired)
  end
end

#resultsObject



149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/rspec-puppet/coverage.rb', line 149

def results
  report = {}

  @collection.delete_if { |name, _| filtered?(name) }

  report[:total] = @collection.size
  report[:touched] = @collection.count { |_, resource| resource.touched? }
  report[:untouched] = report[:total] - report[:touched]
  report[:coverage] = "%5.2f" % ((report[:touched].to_f / report[:total].to_f) * 100)

  report[:resources] = Hash[*@collection.map do |name, wrapper|
    [name, wrapper.to_hash]
  end.flatten]

  text = [
    "Total resources:   #{report[:total]}",
    "Touched resources: #{report[:touched]}",
    "Resource coverage: #{report[:coverage]}%",
  ]

  if report[:untouched] > 0
    text += ['', 'Untouched resources:']
    untouched_resources = report[:resources].reject { |_, r| r[:touched] }
    text += untouched_resources.map { |name, _| "  #{name}" }.sort
  end
  report[:text] = text.join("\n")

  report
end

#run_report(coverage_desired = nil) ⇒ Object



119
120
121
122
123
124
125
126
127
# File 'lib/rspec-puppet/coverage.rb', line 119

def run_report(coverage_desired = nil)
  merge_results if ENV['TEST_ENV_NUMBER']

  report = results

  coverage_test(coverage_desired, report)

  puts report[:text]
end

#save_resultsObject



40
41
42
43
44
45
# File 'lib/rspec-puppet/coverage.rb', line 40

def save_results
  slug = "#{Digest::MD5.hexdigest(Dir.pwd)}-#{Process.pid}"
  File.open(File.join(Dir.tmpdir, "rspec-puppet-coverage-#{slug}"), 'w+') do |f|
    f.puts @collection.to_json
  end
end