Class: Phronomy::Testing::FakeClock
- Inherits:
-
Object
- Object
- Phronomy::Testing::FakeClock
- Defined in:
- lib/phronomy/testing/fake_clock.rb
Overview
A deterministic, manually-advanced clock for use in tests.
Replaces real +Process.clock_gettime+ calls so that time-sensitive code can be tested without relying on wall-clock sleeps.
Instance Attribute Summary collapse
-
#now ⇒ Float
readonly
The current logical time in seconds since the epoch (t=0).
Instance Method Summary collapse
-
#advance(seconds) ⇒ self
private
Advance the clock by +seconds+ and fire any registered callbacks whose deadline has passed.
-
#advance_to_next_timer ⇒ self
private
Advance the clock exactly to the next pending callback and fire it.
-
#at(at) { ... } ⇒ self
private
Register a one-shot callback that fires when the clock reaches +at+.
-
#initialize ⇒ FakeClock
constructor
A new instance of FakeClock.
-
#next_timer_at ⇒ Float?
private
Returns the logical time of the next pending callback, or +nil+ if there are no pending callbacks.
-
#pending_callbacks ⇒ Integer
private
Returns the number of pending (un-fired) callbacks.
-
#pending_timer_entries ⇒ Array<Hash>
private
Returns descriptive entries for all pending callbacks.
-
#schedule(seconds:) { ... } ⇒ self
private
Schedule a one-shot callback to fire after +seconds+ from the current logical time.
Constructor Details
#initialize ⇒ FakeClock
Returns a new instance of FakeClock.
19 20 21 22 23 |
# File 'lib/phronomy/testing/fake_clock.rb', line 19 def initialize @now = 0.0 @callbacks = [] # [[fire_at, block], ...] @mutex = Mutex.new end |
Instance Attribute Details
#now ⇒ Float (readonly)
Returns the current logical time in seconds since the epoch (t=0).
17 18 19 |
# File 'lib/phronomy/testing/fake_clock.rb', line 17 def now @now end |
Instance Method Details
#advance(seconds) ⇒ self
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.
Advance the clock by +seconds+ and fire any registered callbacks whose deadline has passed.
31 32 33 34 35 36 37 |
# File 'lib/phronomy/testing/fake_clock.rb', line 31 def advance(seconds) @mutex.synchronize do @now += seconds.to_f fire_expired_callbacks! end self end |
#advance_to_next_timer ⇒ self
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.
Advance the clock exactly to the next pending callback and fire it. Raises +RuntimeError+ when there are no pending callbacks.
83 84 85 86 87 88 |
# File 'lib/phronomy/testing/fake_clock.rb', line 83 def advance_to_next_timer target = next_timer_at raise "No pending timers to advance to" unless target advance(target - @now) end |
#at(at) { ... } ⇒ self
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.
Register a one-shot callback that fires when the clock reaches +at+.
45 46 47 48 |
# File 'lib/phronomy/testing/fake_clock.rb', line 45 def at(at, &block) @mutex.synchronize { @callbacks << [at.to_f, block] } self end |
#next_timer_at ⇒ Float?
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.
Returns the logical time of the next pending callback, or +nil+ if there are no pending callbacks.
74 75 76 |
# File 'lib/phronomy/testing/fake_clock.rb', line 74 def next_timer_at @mutex.synchronize { @callbacks.min_by { |(t, _)| t }&.first } end |
#pending_callbacks ⇒ Integer
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.
Returns the number of pending (un-fired) callbacks.
65 66 67 |
# File 'lib/phronomy/testing/fake_clock.rb', line 65 def pending_callbacks @mutex.synchronize { @callbacks.size } end |
#pending_timer_entries ⇒ Array<Hash>
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.
Returns descriptive entries for all pending callbacks. Used by Runtime::FakeScheduler#pending_timers.
95 96 97 98 99 |
# File 'lib/phronomy/testing/fake_clock.rb', line 95 def pending_timer_entries @mutex.synchronize do @callbacks.sort_by { |(t, _)| t }.map { |(t, _)| {fire_at: t, description: nil} } end end |
#schedule(seconds:) { ... } ⇒ self
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.
Schedule a one-shot callback to fire after +seconds+ from the current logical time. This is the same interface as Runtime::TimerQueue#schedule so that a +FakeClock+ can be passed as a +timer_queue:+ argument in tests.
58 59 60 |
# File 'lib/phronomy/testing/fake_clock.rb', line 58 def schedule(seconds:, &block) at(@now + seconds.to_f, &block) end |