ghazel-SystemTimer 1.2.1.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|