Module: Upkeep::Rails::Testing
- Defined in:
- lib/upkeep/rails/testing.rb
Overview
Test helpers for asserting the public Upkeep subscription lifecycle from Rails request, integration, and system tests.
Constant Summary collapse
- CHANGE_FACTS_THREAD_KEY =
:upkeep_rails_testing_change_facts
Class Method Summary collapse
-
.capture_broadcasts ⇒ Object
Captures rendered Upkeep delivery payloads while the block runs.
-
.capture_change_facts ⇒ Array(Object, Array<Hash>)
Captures facts passed into Upkeep delivery while the block runs.
-
.capturing_broadcasts? ⇒ Boolean
True when any thread is capturing delivery batches.
-
.capturing_change_facts? ⇒ Boolean
True when the current thread is capturing change facts.
-
.drain_delivery! ⇒ void
Drains the async delivery dispatcher when a test needs deterministic broadcast assertions.
-
.match_report(changes, store: Upkeep::Rails.subscriptions) ⇒ Hash
Runs the invalidation planner against committed-change facts without enqueueing delivery or broadcasting.
-
.record_change_facts(changes) ⇒ Object
Records delivery facts for capture_change_facts.
-
.record_delivery_batch(batch) ⇒ Object
Records a rendered delivery batch for active capture_broadcasts blocks.
Instance Method Summary collapse
-
#activate_upkeep_subscription!(subscription = upkeep_subscription) ⇒ Upkeep::Subscriptions::Subscription
Activates the registered subscription so delivery lookup can find it.
-
#assert_upkeep_subscription_registered(message = nil) ⇒ void
Asserts that the last successful HTML response injected an Upkeep subscription marker and registered a subscription in the configured store.
-
#capture_upkeep_broadcasts(subscription = upkeep_subscription, &block) ⇒ Array<String>
Captures rendered Upkeep broadcasts while the block runs.
-
#capture_upkeep_change_facts(&block) ⇒ Array(Object, Array<Hash>)
Captures facts passed into Upkeep delivery while the block runs.
-
#drain_upkeep_delivery! ⇒ void
Drains async Upkeep delivery for deterministic test assertions.
-
#upkeep_match_report(changes) ⇒ Hash
Returns a dry-run invalidation planner report for one or more change facts against the configured Upkeep subscription store.
-
#upkeep_stream_names(subscription = upkeep_subscription) ⇒ Array<String>
Returns every ActionCable stream name that can receive broadcasts for a subscription, including shared streams.
-
#upkeep_subscription ⇒ Upkeep::Subscriptions::Subscription?
Returns the most recently registered Upkeep subscription.
Class Method Details
.capture_broadcasts ⇒ Object
Captures rendered Upkeep delivery payloads while the block runs. This observes the batch after planning/rendering and before the app-specific transport adapter, so tests stay deterministic across ActionCable adapters.
57 58 59 60 61 62 63 64 65 66 |
# File 'lib/upkeep/rails/testing.rb', line 57 def capture_broadcasts broadcasts = [] broadcast_capture_mutex.synchronize { broadcast_captures << broadcasts } yield drain_delivery! broadcasts.dup ensure broadcast_capture_mutex.synchronize { broadcast_captures.delete(broadcasts) } if broadcasts end |
.capture_change_facts ⇒ Array(Object, Array<Hash>)
Captures facts passed into Upkeep delivery while the block runs. This exposes the same committed-change payloads the planner sees, without broadcasting or altering application code.
29 30 31 32 33 34 35 36 37 |
# File 'lib/upkeep/rails/testing.rb', line 29 def capture_change_facts previous = Thread.current[CHANGE_FACTS_THREAD_KEY] facts = [] Thread.current[CHANGE_FACTS_THREAD_KEY] = facts [yield, facts] ensure Thread.current[CHANGE_FACTS_THREAD_KEY] = previous end |
.capturing_broadcasts? ⇒ Boolean
Returns true when any thread is capturing delivery batches.
69 70 71 |
# File 'lib/upkeep/rails/testing.rb', line 69 def capturing_broadcasts? broadcast_capture_mutex.synchronize { broadcast_captures.any? } end |
.capturing_change_facts? ⇒ Boolean
Returns true when the current thread is capturing change facts.
49 50 51 |
# File 'lib/upkeep/rails/testing.rb', line 49 def capturing_change_facts? !!Thread.current[CHANGE_FACTS_THREAD_KEY] end |
.drain_delivery! ⇒ void
This method returns an undefined value.
Drains the async delivery dispatcher when a test needs deterministic broadcast assertions.
Production code should not call this; normal app delivery runs through the configured adapter.
20 21 22 |
# File 'lib/upkeep/rails/testing.rb', line 20 def drain_delivery! Upkeep::Rails.send(:drain_delivery_dispatcher!) end |
.match_report(changes, store: Upkeep::Rails.subscriptions) ⇒ Hash
Runs the invalidation planner against committed-change facts without enqueueing delivery or broadcasting.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/upkeep/rails/testing.rb', line 96 def match_report(changes, store: Upkeep::Rails.subscriptions) changes = changes.is_a?(Hash) ? [changes] : Array(changes) lookup_payloads = [] subscription = ActiveSupport::Notifications.subscribe("lookup_subscription_index.upkeep") do |event| lookup_payloads << event.payload.dup end plan = Upkeep::Invalidation::Planner.new(store: store).plan(changes) { candidate_entries: plan.candidate_entries.size, matched_entries: plan.matched_entries.size, miss_reason: match_miss_reason(plan, changes, lookup_payloads), targets: plan.targets.map { |target| match_report_target(target) } } ensure ActiveSupport::Notifications.unsubscribe(subscription) if subscription end |
.record_change_facts(changes) ⇒ Object
Records delivery facts for capture_change_facts. Internal test hook; production delivery calls this only when a capture is active.
41 42 43 44 45 46 |
# File 'lib/upkeep/rails/testing.rb', line 41 def record_change_facts(changes) facts = Thread.current[CHANGE_FACTS_THREAD_KEY] return unless facts facts.concat(Array(changes).map { |change| clone_change_fact(change) }) end |
.record_delivery_batch(batch) ⇒ Object
Records a rendered delivery batch for active capture_broadcasts blocks. Internal test hook; production delivery calls this only when a capture is active.
76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/upkeep/rails/testing.rb', line 76 def record_delivery_batch(batch) captures = broadcast_capture_mutex.synchronize { broadcast_captures.dup } return if captures.empty? bodies = batch.envelopes.map(&:body) return if bodies.empty? broadcast_capture_mutex.synchronize do captures.each do |capture| capture.concat(bodies) if broadcast_captures.include?(capture) end end end |
Instance Method Details
#activate_upkeep_subscription!(subscription = upkeep_subscription) ⇒ Upkeep::Subscriptions::Subscription
Activates the registered subscription so delivery lookup can find it.
208 209 210 211 212 213 214 215 |
# File 'lib/upkeep/rails/testing.rb', line 208 def activate_upkeep_subscription!(subscription = upkeep_subscription) raise ArgumentError, "no Upkeep subscription is registered" unless subscription activated = Upkeep::Rails.subscriptions.activate(subscription.id) raise Upkeep::Subscriptions::NotFound, subscription.id unless activated subscription end |
#assert_upkeep_subscription_registered(message = nil) ⇒ void
This method returns an undefined value.
Asserts that the last successful HTML response injected an Upkeep subscription marker and registered a subscription in the configured store.
177 178 179 180 181 |
# File 'lib/upkeep/rails/testing.rb', line 177 def assert_upkeep_subscription_registered( = nil) assert_select "upkeep-subscription-source[data-upkeep-subscription]" assert Upkeep::Rails.subscriptions.subscriptions.any?, || "expected Upkeep to register at least one subscription" end |
#capture_upkeep_broadcasts(subscription = upkeep_subscription, &block) ⇒ Array<String>
Captures rendered Upkeep broadcasts while the block runs. This observes Upkeep after planning/rendering and before the application ActionCable adapter, so tests stay deterministic regardless of the host app’s cable adapter.
225 226 227 228 229 230 |
# File 'lib/upkeep/rails/testing.rb', line 225 def capture_upkeep_broadcasts(subscription = upkeep_subscription, &block) raise ArgumentError, "capture_upkeep_broadcasts requires a block" unless block raise ArgumentError, "no Upkeep subscription is registered" unless subscription Upkeep::Rails::Testing.capture_broadcasts(&block) end |
#capture_upkeep_change_facts(&block) ⇒ Array(Object, Array<Hash>)
Captures facts passed into Upkeep delivery while the block runs.
242 243 244 245 246 |
# File 'lib/upkeep/rails/testing.rb', line 242 def capture_upkeep_change_facts(&block) raise ArgumentError, "capture_upkeep_change_facts requires a block" unless block Upkeep::Rails::Testing.capture_change_facts(&block) end |
#drain_upkeep_delivery! ⇒ void
This method returns an undefined value.
Drains async Upkeep delivery for deterministic test assertions.
235 236 237 |
# File 'lib/upkeep/rails/testing.rb', line 235 def drain_upkeep_delivery! Upkeep::Rails::Testing.drain_delivery! end |
#upkeep_match_report(changes) ⇒ Hash
Returns a dry-run invalidation planner report for one or more change facts against the configured Upkeep subscription store.
253 254 255 |
# File 'lib/upkeep/rails/testing.rb', line 253 def upkeep_match_report(changes) Upkeep::Rails::Testing.match_report(changes) end |
#upkeep_stream_names(subscription = upkeep_subscription) ⇒ Array<String>
Returns every ActionCable stream name that can receive broadcasts for a subscription, including shared streams.
196 197 198 199 200 |
# File 'lib/upkeep/rails/testing.rb', line 196 def upkeep_stream_names(subscription = upkeep_subscription) raise ArgumentError, "no Upkeep subscription is registered" unless subscription ([subscription..fetch(:stream_name)] + subscription..fetch(:shared_stream_names, [])).uniq end |
#upkeep_subscription ⇒ Upkeep::Subscriptions::Subscription?
Returns the most recently registered Upkeep subscription.
186 187 188 |
# File 'lib/upkeep/rails/testing.rb', line 186 def upkeep_subscription Upkeep::Rails.subscriptions.subscriptions.last end |