Module: RSpecTracer::Storage::JsonBackend::Merger Private
- Defined in:
- lib/rspec_tracer/storage/json_backend.rb
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Stateless snapshot union. parallel_tests partitions spec files across workers, so example IDs are disjoint in practice - the merge collision rules (first-wins for metadata, sum-of-ints for per-line coverage) only fire on collaborating workers that happened to observe the same input file.
Class Method Summary collapse
-
.absorb(state, snapshot) ⇒ Object
private
Union every field from one peer snapshot into the running state.
-
.build_merged_snapshot(state, schema_version:) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.call(snapshots, schema_version:) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.empty_state ⇒ Object
private
Internal helper for the tracer pipeline.
-
.merge_env_dependency!(target, source) ⇒ Object
private
Per-example env attribution unions set-wise: an example that declared ‘tracks: { env: [A, B] }` on one worker and `tracks: { env: [B, C] }` on another (edge case; parallel_tests workers rarely run the same example) collapses to [A, B, C].
-
.merge_examples_coverage!(target, source) ⇒ Object
private
Internal helper for the tracer pipeline.
-
.merge_filtered_examples!(target, source) ⇒ Object
private
Merge per-worker filtered_examples by example_id.
-
.reverse_of(dependency) ⇒ Object
private
Internal helper for the tracer pipeline.
Class Method Details
.absorb(state, snapshot) ⇒ Object
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.
Union every field from one peer snapshot into the running state. Each field has a distinct combine rule (merge-first-wins, Set#merge, concat, or summing coverage strengths), so the branching is inherent to the shape. Decomposing per-field would scatter the merge contract. rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 458 def self.absorb(state, snapshot) state[:all_examples].merge!(snapshot.all_examples || {}) { |_, v, _| v } (snapshot.duplicate_examples || {}).each do |id, entries| state[:duplicate_examples][id].concat(entries) end state[:interrupted_examples].merge(snapshot.interrupted_examples || Set.new) state[:flaky_examples].merge(snapshot.flaky_examples || Set.new) state[:failed_examples].merge(snapshot.failed_examples || Set.new) state[:pending_examples].merge(snapshot.pending_examples || Set.new) state[:skipped_examples].merge(snapshot.skipped_examples || Set.new) state[:all_files].merge!(snapshot.all_files || {}) { |_, v, _| v } (snapshot.dependency || {}).each do |id, paths| state[:dependency][id].merge(paths) end merge_examples_coverage!(state[:examples_coverage], snapshot.examples_coverage || {}) state[:boot_set].merge!(snapshot.boot_set || {}) state[:wsi_snapshot].merge!(snapshot.wsi_snapshot || {}) state[:env_snapshot].merge!(snapshot.env_snapshot || {}) merge_env_dependency!(state[:env_dependency], snapshot.env_dependency || {}) merge_filtered_examples!(state[:filtered_examples], snapshot.filtered_examples || {}) end |
.build_merged_snapshot(state, schema_version:) ⇒ Object
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.
Internal helper for the tracer pipeline.
406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 406 def self.build_merged_snapshot(state, schema_version:) Snapshot.new( schema_version: schema_version, run_id: state[:run_id], all_examples: state[:all_examples], duplicate_examples: state[:duplicate_examples], interrupted_examples: state[:interrupted_examples], flaky_examples: state[:flaky_examples], failed_examples: state[:failed_examples], pending_examples: state[:pending_examples], skipped_examples: state[:skipped_examples], all_files: state[:all_files], dependency: state[:dependency], reverse_dependency: state[:reverse_dependency], examples_coverage: state[:examples_coverage], boot_set: state[:boot_set], wsi_snapshot: state[:wsi_snapshot], env_snapshot: state[:env_snapshot], env_dependency: state[:env_dependency], cache_hit_reason: state[:cache_hit_reason], filtered_examples: state[:filtered_examples] ) end |
.call(snapshots, schema_version:) ⇒ Object
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.
Internal helper for the tracer pipeline.
393 394 395 396 397 398 399 400 401 402 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 393 def self.call(snapshots, schema_version:) state = empty_state snapshots.each { |s| absorb(state, s) } state[:reverse_dependency] = reverse_of(state[:dependency]) state[:run_id] = Digest::MD5.hexdigest(state[:all_examples].keys.sort.to_json) state[:cache_hit_reason] = state[:filtered_examples].values.tally build_merged_snapshot(state, schema_version: schema_version) end |
.empty_state ⇒ Object
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.
Internal helper for the tracer pipeline.
432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 432 def self.empty_state { all_examples: {}, duplicate_examples: Hash.new { |h, k| h[k] = [] }, interrupted_examples: Set.new, flaky_examples: Set.new, failed_examples: Set.new, pending_examples: Set.new, skipped_examples: Set.new, all_files: {}, dependency: Hash.new { |h, k| h[k] = Set.new }, examples_coverage: {}, boot_set: {}, wsi_snapshot: {}, env_snapshot: {}, env_dependency: {}, filtered_examples: {} } end |
.merge_env_dependency!(target, source) ⇒ Object
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.
Per-example env attribution unions set-wise: an example that declared ‘tracks: { env: [A, B] }` on one worker and `tracks: { env: [B, C] }` on another (edge case; parallel_tests workers rarely run the same example) collapses to [A, B, C].
485 486 487 488 489 490 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 485 def self.merge_env_dependency!(target, source) source.each do |id, names| existing = target[id] || [] target[id] = (existing | Array(names)).sort end end |
.merge_examples_coverage!(target, source) ⇒ Object
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.
Internal helper for the tracer pipeline.
510 511 512 513 514 515 516 517 518 519 520 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 510 def self.merge_examples_coverage!(target, source) source.each do |id, per_file| entry = target[id] ||= {} per_file.each do |file_path, lines| file_entry = entry[file_path] ||= {} lines.each do |line_key, strength| file_entry[line_key] = (file_entry[line_key] || 0) + (strength || 0) end end end end |
.merge_filtered_examples!(target, source) ⇒ Object
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.
Merge per-worker filtered_examples by example_id. Every parallel_tests worker independently runs Filter.select against the same global previous-run snapshot (Engine#compute_filter_decisions walks the registry seeded from ‘prev` and the filter intersects against `prev.all_examples.keys`), so every worker’s filtered_examples hash is IDENTICAL. First-write-wins collapses the duplicate ids; ‘Merger.call` re-derives `cache_hit_reason` as the values-tally of the merged hash so the merged cache_hit_reason is the per-id-correct count (not the N-fold-inflated sum of identical per-worker tallies that the pre-#193 merge produced).
504 505 506 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 504 def self.merge_filtered_examples!(target, source) source.each { |id, reason| target[id] ||= reason } end |
.reverse_of(dependency) ⇒ Object
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.
Internal helper for the tracer pipeline.
524 525 526 527 528 529 530 |
# File 'lib/rspec_tracer/storage/json_backend.rb', line 524 def self.reverse_of(dependency) reverse = Hash.new { |h, k| h[k] = Set.new } dependency.each do |id, file_names| file_names.each { |name| reverse[name] << id } end reverse end |