ghazel-SystemTimer 1.2.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/COPYING +340 -0
- data/ChangeLog +51 -0
- data/LICENSE +58 -0
- data/README +196 -0
- data/ext/system_timer/extconf.rb +3 -0
- data/ext/system_timer/system_timer_native.c +325 -0
- data/lib/system_timer.rb +115 -0
- data/lib/system_timer/concurrent_timer_pool.rb +89 -0
- data/lib/system_timer/thread_timer.rb +22 -0
- data/lib/system_timer_stub.rb +20 -0
- data/test/all_tests.rb +3 -0
- data/test/system_timer/concurrent_timer_pool_unit_test.rb +291 -0
- data/test/system_timer/thread_timer_test.rb +20 -0
- data/test/system_timer_functional_test.rb +282 -0
- data/test/system_timer_unit_test.rb +110 -0
- data/test/test_helper.rb +10 -0
- metadata +75 -0
data/lib/system_timer.rb
ADDED
@@ -0,0 +1,115 @@
|
|
1
|
+
# Copyright 2008 David Vollbracht & Philippe Hanrigou
|
2
|
+
|
3
|
+
if RUBY_PLATFORM =~ /mswin|mingw/ or (defined?(RUBY_ENGINE) and RUBY_ENGINE == "rbx")
|
4
|
+
require File.dirname(__FILE__) + '/system_timer_stub'
|
5
|
+
else
|
6
|
+
|
7
|
+
require 'rubygems'
|
8
|
+
require 'timeout'
|
9
|
+
require 'forwardable'
|
10
|
+
require 'monitor'
|
11
|
+
require File.dirname(__FILE__) + '/system_timer/thread_timer'
|
12
|
+
require File.dirname(__FILE__) + '/system_timer/concurrent_timer_pool'
|
13
|
+
|
14
|
+
# Timer based on underlying +ITIMER_REAL+ system timer. It is a
|
15
|
+
# solution to Ruby processes which hang beyond the time limit when accessing
|
16
|
+
# external resources. This is useful when timeout.rb, which relies on green
|
17
|
+
# threads, does not work consistently.
|
18
|
+
#
|
19
|
+
# For more information and background check out:
|
20
|
+
#
|
21
|
+
# * http://ph7spot.com/articles/system_timer
|
22
|
+
# * http://davidvollbracht.com/2008/6/2/30-days-of-teach-day-1-systemtimer
|
23
|
+
#
|
24
|
+
# == Usage
|
25
|
+
#
|
26
|
+
# require 'systemtimer'
|
27
|
+
#
|
28
|
+
# SystemTimer.timeout_after(5) do
|
29
|
+
#
|
30
|
+
# # Something that should be interrupted if it takes too much time...
|
31
|
+
# # ... even if blocked on a system call!
|
32
|
+
#
|
33
|
+
# end
|
34
|
+
#
|
35
|
+
module SystemTimer
|
36
|
+
|
37
|
+
Thread.exclusive do # Avoid race conditions for monitor and pool creation
|
38
|
+
@timer_pool = ConcurrentTimerPool.new
|
39
|
+
@monitor = Monitor.new
|
40
|
+
end
|
41
|
+
|
42
|
+
class << self
|
43
|
+
attr_reader :timer_pool
|
44
|
+
|
45
|
+
# Executes the method's block. If the block execution terminates before
|
46
|
+
# +seconds+ seconds has passed, it returns true. If not, it terminates
|
47
|
+
# the execution and raises a +Timeout::Error+.
|
48
|
+
def timeout_after(seconds, exception_class = nil)
|
49
|
+
new_timer = nil # just for scope
|
50
|
+
@monitor.synchronize do
|
51
|
+
new_timer = timer_pool.add_timer seconds, exception_class
|
52
|
+
timer_interval = timer_pool.next_trigger_interval_in_seconds
|
53
|
+
debug "==== Install Timer ==== at #{Time.now.to_f}, next interval: #{timer_interval}"
|
54
|
+
if timer_pool.first_timer?
|
55
|
+
install_first_timer_and_save_original_configuration timer_interval
|
56
|
+
else
|
57
|
+
install_next_timer timer_interval
|
58
|
+
end
|
59
|
+
end
|
60
|
+
return yield
|
61
|
+
ensure
|
62
|
+
@monitor.synchronize do
|
63
|
+
debug "==== Cleanup Timer ==== at #{Time.now.to_f}, #{new_timer} "
|
64
|
+
timer_pool.cancel new_timer
|
65
|
+
timer_pool.log_registered_timers if debug_enabled?
|
66
|
+
next_interval = timer_pool.next_trigger_interval_in_seconds
|
67
|
+
debug "Cleanup Timer : next interval #{next_interval.inspect} "
|
68
|
+
if next_interval
|
69
|
+
install_next_timer next_interval
|
70
|
+
else
|
71
|
+
restore_original_configuration
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Backward compatibility with timeout.rb
|
77
|
+
alias timeout timeout_after
|
78
|
+
|
79
|
+
protected
|
80
|
+
|
81
|
+
def install_ruby_sigalrm_handler #:nodoc:
|
82
|
+
@original_ruby_sigalrm_handler = trap('SIGALRM') do
|
83
|
+
@monitor.synchronize do
|
84
|
+
# Triggers timers one at a time to ensure more deterministic results
|
85
|
+
timer_pool.trigger_next_expired_timer
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def restore_original_ruby_sigalrm_handler #:nodoc:
|
91
|
+
trap('SIGALRM', original_ruby_sigalrm_handler || 'DEFAULT')
|
92
|
+
ensure
|
93
|
+
reset_original_ruby_sigalrm_handler
|
94
|
+
end
|
95
|
+
|
96
|
+
def original_ruby_sigalrm_handler #:nodoc:
|
97
|
+
@original_ruby_sigalrm_handler
|
98
|
+
end
|
99
|
+
|
100
|
+
def reset_original_ruby_sigalrm_handler #:nodoc:
|
101
|
+
@original_ruby_sigalrm_handler = nil
|
102
|
+
end
|
103
|
+
|
104
|
+
def debug(message) #:nodoc
|
105
|
+
puts message if debug_enabled?
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
|
112
|
+
require 'system_timer_native'
|
113
|
+
|
114
|
+
|
115
|
+
end # stub guard
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# Copyright 2008 David Vollbracht & Philippe Hanrigou
|
2
|
+
|
3
|
+
module SystemTimer
|
4
|
+
|
5
|
+
class ConcurrentTimerPool
|
6
|
+
|
7
|
+
def registered_timers
|
8
|
+
@timers ||= []
|
9
|
+
end
|
10
|
+
|
11
|
+
def register_timer(trigger_time, thread, exception_class=nil)
|
12
|
+
new_timer = ThreadTimer.new(trigger_time, thread, exception_class)
|
13
|
+
registered_timers << new_timer
|
14
|
+
new_timer
|
15
|
+
end
|
16
|
+
|
17
|
+
def add_timer(interval_in_seconds, exception_class=nil)
|
18
|
+
new_timer = register_timer(Time.now.to_f + interval_in_seconds, Thread.current, exception_class)
|
19
|
+
log_registered_timers if SystemTimer.debug_enabled?
|
20
|
+
new_timer
|
21
|
+
end
|
22
|
+
|
23
|
+
def cancel(registered_timer)
|
24
|
+
registered_timers.delete registered_timer
|
25
|
+
end
|
26
|
+
|
27
|
+
def first_timer?
|
28
|
+
registered_timers.size == 1
|
29
|
+
end
|
30
|
+
|
31
|
+
def next_timer
|
32
|
+
registered_timers.sort {|x,y| x.trigger_time <=> y.trigger_time}.first
|
33
|
+
end
|
34
|
+
|
35
|
+
def next_trigger_time
|
36
|
+
timer = next_timer
|
37
|
+
timer.trigger_time unless timer.nil?
|
38
|
+
end
|
39
|
+
|
40
|
+
def next_trigger_interval_in_seconds
|
41
|
+
timer = next_timer
|
42
|
+
[0, (timer.trigger_time - Time.now.to_f)].max unless timer.nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
def next_expired_timer(now_in_seconds_since_epoch)
|
46
|
+
candidate_timer = next_timer
|
47
|
+
if SystemTimer.debug_enabled?
|
48
|
+
puts "Candidate timer at #{now_in_seconds_since_epoch} : " +
|
49
|
+
candidate_timer.inspect
|
50
|
+
end
|
51
|
+
return nil if candidate_timer.nil? ||
|
52
|
+
candidate_timer.trigger_time > now_in_seconds_since_epoch
|
53
|
+
candidate_timer
|
54
|
+
end
|
55
|
+
|
56
|
+
def trigger_next_expired_timer_at(now_in_seconds_since_epoch)
|
57
|
+
timer = next_expired_timer(now_in_seconds_since_epoch)
|
58
|
+
puts "Next expired timer : #{timer.inspect}" if SystemTimer.debug_enabled?
|
59
|
+
return if timer.nil?
|
60
|
+
|
61
|
+
cancel timer
|
62
|
+
log_timeout_received(timer) if SystemTimer.debug_enabled?
|
63
|
+
timer.thread.raise timer.exception_class.new("time's up!")
|
64
|
+
end
|
65
|
+
|
66
|
+
def trigger_next_expired_timer
|
67
|
+
puts "Trigger next expired timer" if SystemTimer.debug_enabled?
|
68
|
+
trigger_next_expired_timer_at Time.now.to_f
|
69
|
+
end
|
70
|
+
|
71
|
+
def log_timeout_received(thread_timer) #:nodoc:
|
72
|
+
puts <<-EOS
|
73
|
+
==== Triger Timer ==== #{thread_timer}
|
74
|
+
Main thread : #{Thread.main}
|
75
|
+
Timed_thread : #{thread_timer.thread}
|
76
|
+
All Threads : #{Thread.list.inspect}
|
77
|
+
EOS
|
78
|
+
log_registered_timers
|
79
|
+
end
|
80
|
+
|
81
|
+
def log_registered_timers #:nodoc:
|
82
|
+
puts <<-EOS
|
83
|
+
Registered Timers: #{registered_timers.map {|t| t.to_s}.join("\n ")}
|
84
|
+
EOS
|
85
|
+
end
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright 2008 David Vollbracht & Philippe Hanrigou
|
2
|
+
|
3
|
+
module SystemTimer
|
4
|
+
|
5
|
+
# Timer saving associated thread. This is needed because we trigger timers
|
6
|
+
# from a Ruby signal handler and Ruby signals are always delivered to
|
7
|
+
# main thread.
|
8
|
+
class ThreadTimer
|
9
|
+
attr_reader :trigger_time, :thread, :exception_class
|
10
|
+
|
11
|
+
def initialize(trigger_time, thread, exception_class = nil)
|
12
|
+
@trigger_time = trigger_time
|
13
|
+
@thread = thread
|
14
|
+
@exception_class = exception_class || Timeout::Error
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_s
|
18
|
+
"<ThreadTimer :time => #{trigger_time}, :thread => #{thread}, :exception_class => #{exception_class}>"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# Copyright 2008 David Vollbracht & Philippe Hanrigou
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'timeout'
|
5
|
+
|
6
|
+
module SystemTimer
|
7
|
+
class << self
|
8
|
+
|
9
|
+
def timeout_after(seconds)
|
10
|
+
Timeout::timeout(seconds) do
|
11
|
+
yield
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
# Backward compatibility with timeout.rb
|
16
|
+
alias timeout timeout_after
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/test/all_tests.rb
ADDED
@@ -0,0 +1,291 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../test_helper'
|
2
|
+
|
3
|
+
unit_tests do
|
4
|
+
|
5
|
+
test "registered_timers is empty when there is no registered timers" do
|
6
|
+
assert_equal [], SystemTimer::ConcurrentTimerPool.new.registered_timers
|
7
|
+
end
|
8
|
+
|
9
|
+
test "a new timer is added to the registered timer list when you register a timer" do
|
10
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
11
|
+
pool.register_timer :a_trigger_time, :a_thread
|
12
|
+
assert_equal [[:a_trigger_time, :a_thread]],
|
13
|
+
pool.registered_timers.collect {|t| [t.trigger_time, t.thread] }
|
14
|
+
end
|
15
|
+
|
16
|
+
test "register_timer returns the timer that was just added to the pool" do
|
17
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
18
|
+
timer = pool.register_timer :a_trigger_time, :a_thread
|
19
|
+
assert_equal [:a_trigger_time, :a_thread], [timer.trigger_time, timer.thread]
|
20
|
+
end
|
21
|
+
|
22
|
+
test "add_timer is a shortcut method to register a timer given its interval" do
|
23
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
24
|
+
Thread.stubs(:current).returns(:the_current_thread)
|
25
|
+
now = Time.now
|
26
|
+
Time.stubs(:now).returns(now)
|
27
|
+
|
28
|
+
pool.expects(:register_timer).with(now.to_f + 15, :the_current_thread, nil)
|
29
|
+
pool.add_timer 15
|
30
|
+
end
|
31
|
+
|
32
|
+
test "cancel removes a timer from the registered timer list" do
|
33
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
34
|
+
registered_timer = pool.register_timer :a_trigger_time, :a_thread
|
35
|
+
pool.cancel registered_timer
|
36
|
+
assert_equal [], pool.registered_timers
|
37
|
+
end
|
38
|
+
|
39
|
+
test "cancel does not complain when timer is cancelled " +
|
40
|
+
"(useful for ensure blocks)" do
|
41
|
+
|
42
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
43
|
+
a_timer = pool.add_timer 123
|
44
|
+
another_timer = pool.add_timer 456
|
45
|
+
pool.cancel(another_timer)
|
46
|
+
pool.cancel(another_timer)
|
47
|
+
assert_equal [a_timer], pool.registered_timers
|
48
|
+
end
|
49
|
+
|
50
|
+
test "first_timer? returns false when there is no timer" do
|
51
|
+
assert_equal false, SystemTimer::ConcurrentTimerPool.new.first_timer?
|
52
|
+
end
|
53
|
+
|
54
|
+
test "first_timer? returns true when there is a single timer" do
|
55
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
56
|
+
pool.add_timer 7
|
57
|
+
assert_equal true, pool.first_timer?
|
58
|
+
end
|
59
|
+
|
60
|
+
test "first_timer? returns false when there is more than one timer" do
|
61
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
62
|
+
pool.add_timer 7
|
63
|
+
pool.add_timer 3
|
64
|
+
assert_equal false, pool.first_timer?
|
65
|
+
end
|
66
|
+
|
67
|
+
test "first_timer? returns false when there is a single timer left" do
|
68
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
69
|
+
first_timer = pool.add_timer 7
|
70
|
+
pool.add_timer 3
|
71
|
+
pool.cancel first_timer
|
72
|
+
assert_equal true, pool.first_timer?
|
73
|
+
end
|
74
|
+
|
75
|
+
test "next expired timer return nil when there is no registered timer" do
|
76
|
+
assert_nil SystemTimer::ConcurrentTimerPool.new.next_expired_timer(24)
|
77
|
+
end
|
78
|
+
|
79
|
+
test "next_timer returns nil when there is no registered timer" do
|
80
|
+
assert_nil SystemTimer::ConcurrentTimerPool.new.next_timer
|
81
|
+
end
|
82
|
+
|
83
|
+
test "next_timer returns the registered timer when " +
|
84
|
+
"there is only one registered timer" do
|
85
|
+
|
86
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
87
|
+
the_timer = pool.register_timer 24, stub_everything
|
88
|
+
assert_equal the_timer, pool.next_timer
|
89
|
+
end
|
90
|
+
|
91
|
+
test "next_timer returns the trigger time of the first timer to" +
|
92
|
+
"expire when there is more than one registered timer" do
|
93
|
+
|
94
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
95
|
+
late_timer = pool.register_timer 64, stub_everything
|
96
|
+
early_timer = pool.register_timer 24, stub_everything
|
97
|
+
assert_equal early_timer, pool.next_timer
|
98
|
+
end
|
99
|
+
|
100
|
+
test "next_trigger_time returns nil when next_timer is nil" do
|
101
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
102
|
+
pool.expects(:next_timer).returns(nil)
|
103
|
+
assert_nil pool.next_trigger_time
|
104
|
+
end
|
105
|
+
|
106
|
+
test "next_trigger_time returns trigger time of next timer when " +
|
107
|
+
"next timer is not nil" do
|
108
|
+
|
109
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
110
|
+
the_timer = SystemTimer::ThreadTimer.new 24, stub_everything
|
111
|
+
pool.expects(:next_timer).returns(the_timer)
|
112
|
+
assert_equal 24, pool.next_trigger_time
|
113
|
+
end
|
114
|
+
|
115
|
+
test "next_trigger_interval_in_seconds returns nil when next_timer is nil" do
|
116
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
117
|
+
pool.expects(:next_timer).returns(nil)
|
118
|
+
assert_nil pool.next_trigger_interval_in_seconds
|
119
|
+
end
|
120
|
+
|
121
|
+
test "next_trigger_interval_in_seconds returns the interval between now and " +
|
122
|
+
"next_timer timer time when next timer is in the future" do
|
123
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
124
|
+
now = Time.now
|
125
|
+
Time.stubs(:now).returns(now)
|
126
|
+
next_timer = SystemTimer::ThreadTimer.new((now.to_f + 7), stub_everything)
|
127
|
+
pool.expects(:next_timer).returns(next_timer)
|
128
|
+
assert_equal 7, pool.next_trigger_interval_in_seconds
|
129
|
+
end
|
130
|
+
|
131
|
+
test "next_trigger_interval_in_seconds returns 0 when next timer is now" do
|
132
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
133
|
+
now = Time.now
|
134
|
+
Time.stubs(:now).returns(now)
|
135
|
+
next_timer = SystemTimer::ThreadTimer.new now.to_f, stub_everything
|
136
|
+
pool.expects(:next_timer).returns(next_timer)
|
137
|
+
assert_equal 0, pool.next_trigger_interval_in_seconds
|
138
|
+
end
|
139
|
+
|
140
|
+
test "next_trigger_interval_in_seconds returns 0 when next timer is in the past" do
|
141
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
142
|
+
now = Time.now
|
143
|
+
Time.stubs(:now).returns(now)
|
144
|
+
next_timer = SystemTimer::ThreadTimer.new((now.to_f - 3), stub_everything)
|
145
|
+
pool.expects(:next_timer).returns(next_timer)
|
146
|
+
assert_equal 0, pool.next_trigger_interval_in_seconds
|
147
|
+
end
|
148
|
+
|
149
|
+
test "next_expired_timer returns the timer that was trigerred" +
|
150
|
+
"when a timer has expired" do
|
151
|
+
|
152
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
153
|
+
the_timer = pool.register_timer 24, :a_thread
|
154
|
+
assert_equal the_timer, pool.next_expired_timer(24)
|
155
|
+
end
|
156
|
+
|
157
|
+
test "next_expired_timer returns nil when no timer has expired yet" do
|
158
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
159
|
+
pool.register_timer 24, :a_thread
|
160
|
+
assert_nil pool.next_expired_timer(23)
|
161
|
+
end
|
162
|
+
|
163
|
+
test "next_expired_timer returns the timer that first expired " +
|
164
|
+
"when there is more than one expired timer" do
|
165
|
+
|
166
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
167
|
+
last_to_expire = pool.register_timer 64, :a_thread
|
168
|
+
first_to_expire = pool.register_timer 24, :a_thread
|
169
|
+
assert_equal first_to_expire, pool.next_expired_timer(100)
|
170
|
+
end
|
171
|
+
|
172
|
+
test "trigger_next_expired_timer_at does not raise when there is no registered timer" do
|
173
|
+
SystemTimer::ConcurrentTimerPool.new.trigger_next_expired_timer_at 1234
|
174
|
+
end
|
175
|
+
|
176
|
+
test "trigger_next_expired_timer_at raises a TimeoutError in the context of " +
|
177
|
+
"its thread when there is a registered timer that has expired" do
|
178
|
+
|
179
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
180
|
+
the_thread = mock('thread')
|
181
|
+
|
182
|
+
Timeout::Error.expects(:new).with("time's up!").returns(:the_exception)
|
183
|
+
the_thread.expects(:raise).with(:the_exception)
|
184
|
+
pool.register_timer 24, the_thread
|
185
|
+
pool.trigger_next_expired_timer_at 24
|
186
|
+
end
|
187
|
+
|
188
|
+
test "trigger_next_expired_timer_at does not raise when registered timer has not expired" do
|
189
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
190
|
+
pool.register_timer 24, stub_everything
|
191
|
+
pool.trigger_next_expired_timer_at(10)
|
192
|
+
end
|
193
|
+
|
194
|
+
test "trigger_next_expired_timer_at triggers the first registered timer that expired" do
|
195
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
196
|
+
first_to_expire = pool.register_timer 24, stub_everything
|
197
|
+
second_to_expire = pool.register_timer 64, stub_everything
|
198
|
+
pool.trigger_next_expired_timer_at(100)
|
199
|
+
assert_equal [second_to_expire], pool.registered_timers
|
200
|
+
end
|
201
|
+
|
202
|
+
test "trigger_next_expired_timer_at triggers the first registered timer that " +
|
203
|
+
"expired whatever the timer insertion order is" do
|
204
|
+
|
205
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
206
|
+
second_to_expire = pool.register_timer 64, stub_everything
|
207
|
+
first_to_expire = pool.register_timer 24, stub_everything
|
208
|
+
pool.trigger_next_expired_timer_at(100)
|
209
|
+
assert_equal [second_to_expire], pool.registered_timers
|
210
|
+
end
|
211
|
+
|
212
|
+
test "trigger_next_expired_timer_at remove the expired timer from the pool" do
|
213
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
214
|
+
pool.register_timer 24, stub_everything
|
215
|
+
pool.trigger_next_expired_timer_at 24
|
216
|
+
end
|
217
|
+
|
218
|
+
test "trigger_next_expired_timer_at logs timeout a registered timer has expired" +
|
219
|
+
"and SystemTimer debug mode is enabled " do
|
220
|
+
|
221
|
+
original_stdout = $stdout
|
222
|
+
begin
|
223
|
+
stdout = StringIO.new
|
224
|
+
$stdout = stdout
|
225
|
+
|
226
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
227
|
+
the_timer = pool.register_timer 24, stub_everything
|
228
|
+
SystemTimer.stubs(:debug_enabled?).returns(true)
|
229
|
+
|
230
|
+
pool.expects(:log_timeout_received).with(the_timer)
|
231
|
+
pool.trigger_next_expired_timer_at 24
|
232
|
+
ensure
|
233
|
+
$stdout = original_stdout
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
test "trigger_next_expired_timer_at does not logs timeoout when SystemTimer " +
|
238
|
+
"debug mode is disabled " do
|
239
|
+
|
240
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
241
|
+
the_timer = pool.register_timer 24, stub_everything
|
242
|
+
SystemTimer.stubs(:debug_enabled?).returns(false)
|
243
|
+
|
244
|
+
pool.expects(:log_timeout_received).never
|
245
|
+
pool.trigger_next_expired_timer_at 24
|
246
|
+
end
|
247
|
+
|
248
|
+
test "trigger_next_expired_timer_at does not logs timeout no registered timer " +
|
249
|
+
"has expired and SystemTimer debug mode is enabled " do
|
250
|
+
|
251
|
+
original_stdout = $stdout
|
252
|
+
begin
|
253
|
+
stdout = StringIO.new
|
254
|
+
$stdout = stdout
|
255
|
+
|
256
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
257
|
+
the_timer = pool.register_timer 24, stub_everything
|
258
|
+
SystemTimer.stubs(:debug_enabled?).returns(true)
|
259
|
+
|
260
|
+
pool.expects(:log_timeout_received).never
|
261
|
+
pool.trigger_next_expired_timer_at 23
|
262
|
+
ensure
|
263
|
+
$stdout = original_stdout
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
test "trigger_next_expired_timer is a shorcut method calling " +
|
268
|
+
"trigger_next_expired_timer_at with current epoch time" do
|
269
|
+
|
270
|
+
now = Time.now
|
271
|
+
pool = SystemTimer::ConcurrentTimerPool.new
|
272
|
+
Time.stubs(:now).returns(now)
|
273
|
+
|
274
|
+
pool.expects(:trigger_next_expired_timer_at).with(now.to_f)
|
275
|
+
pool.trigger_next_expired_timer
|
276
|
+
end
|
277
|
+
|
278
|
+
test "log_timeout_received does not raise" do
|
279
|
+
original_stdout = $stdout
|
280
|
+
begin
|
281
|
+
stdout = StringIO.new
|
282
|
+
$stdout = stdout
|
283
|
+
|
284
|
+
SystemTimer::ConcurrentTimerPool.new.log_timeout_received(SystemTimer::ThreadTimer.new(:a_time, :a_thread))
|
285
|
+
assert_match %r{==== Triger Timer ====}, stdout.string
|
286
|
+
ensure
|
287
|
+
$stdout = original_stdout
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
end
|