Module: RSpec::FlakeClassifier::Integrations::RSpecHermetic

Defined in:
lib/rspec/flake/classifier/integrations.rb

Class Method Summary collapse

Class Method Details

.change_summary(change) ⇒ Object



159
160
161
# File 'lib/rspec/flake/classifier/integrations.rb', line 159

def change_summary(change)
  "#{change.probe}:#{change.key} #{stable_value(change.before)} -> #{stable_value(change.after)}"
end

.collect_individual(receivers, example) ⇒ Object



124
125
126
127
128
129
130
# File 'lib/rspec/flake/classifier/integrations.rb', line 124

def collect_individual(receivers, example)
  {
    resources: Integrations.call_first(receivers, %i[resources_for resource_leaks_for leaks_for], example),
    files: Integrations.call_first(receivers, %i[files_for filesystem_for], example),
    sockets: Integrations.call_first(receivers, %i[sockets_for network_for], example)
  }.compact
end

.evidence_for(changes, pattern) ⇒ Object



154
155
156
157
# File 'lib/rspec/flake/classifier/integrations.rb', line 154

def evidence_for(changes, pattern)
  changes.select { |change| change.probe.to_s.match?(pattern) || change.key.to_s.match?(pattern) }
         .map { |change| change_summary(change) }
end

.missing_value?(value) ⇒ Boolean

Returns:

  • (Boolean)


169
170
171
172
# File 'lib/rspec/flake/classifier/integrations.rb', line 169

def missing_value?(value)
  change = Integrations.constant("RSpec::Hermetic::Change")
  change && change.const_defined?(:MISSING) && value.equal?(change.const_get(:MISSING))
end

.normalize_hash(value) ⇒ Object



174
175
176
177
178
179
180
181
182
183
# File 'lib/rspec/flake/classifier/integrations.rb', line 174

def normalize_hash(value)
  return value.to_h if value.respond_to?(:to_h)

  {
    resources: value.respond_to?(:resources) ? value.resources : nil,
    files: value.respond_to?(:files) ? value.files : nil,
    sockets: value.respond_to?(:sockets) ? value.sockets : nil,
    source: value.respond_to?(:source) ? value.source : nil
  }.compact
end

.normalize_record(record) ⇒ Object



143
144
145
146
147
148
149
150
151
152
# File 'lib/rspec/flake/classifier/integrations.rb', line 143

def normalize_record(record)
  changes = Array((record[:changes] || record["changes"])&.changes)
  evidence = changes.map { |change| change_summary(change) }
  {
    resources: evidence_for(changes, /resource|runtime|global|constant|env|random|time|rails/i),
    files: evidence_for(changes, /file|filesystem|tmp|dir/i),
    sockets: evidence_for(changes, /socket|network|tcp|udp|http/i),
    source: evidence.join("\n")
  }.compact
end

.probe_for(example) ⇒ Object



103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# File 'lib/rspec/flake/classifier/integrations.rb', line 103

def probe_for(example)
  Integrations.try_require("rspec/hermetic")
  record = runner_record(example)
  return normalize_record(record) if record

  receivers = [
    Integrations.constant("RSpec::Hermetic"),
    Integrations.constant("RSpec::Hermetic::Forensic"),
    Integrations.constant("RSpec::Hermetic::Probe"),
    Integrations.constant("Rspec::Hermetic")
  ]
  value = Integrations.call_first(
    receivers,
    %i[evidence_for forensic_for probe_for result_for for_example],
    example
  )
  return normalize_hash(value) if value

  collect_individual(receivers, example)
end

.runner_record(example) ⇒ Object



132
133
134
135
136
137
138
139
140
141
# File 'lib/rspec/flake/classifier/integrations.rb', line 132

def runner_record(example)
  hermetic = Integrations.constant("RSpec::Hermetic")
  return nil unless hermetic&.respond_to?(:runner)
  return nil unless hermetic.runner&.respond_to?(:records)

  hermetic.runner.records.reverse.find do |record|
    candidate = record[:example] || record["example"]
    candidate.equal?(example) || candidate&.respond_to?(:id) && candidate.id == example.id
  end
end

.stable_value(value) ⇒ Object



163
164
165
166
167
# File 'lib/rspec/flake/classifier/integrations.rb', line 163

def stable_value(value)
  return "<missing>" if missing_value?(value)

  value.inspect
end