concurrent-ruby 0.2.1 → 0.2.2
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.
- checksums.yaml +7 -0
- data/LICENSE +21 -21
- data/README.md +276 -275
- data/lib/concurrent.rb +28 -28
- data/lib/concurrent/agent.rb +114 -114
- data/lib/concurrent/cached_thread_pool.rb +131 -131
- data/lib/concurrent/defer.rb +65 -65
- data/lib/concurrent/event.rb +60 -60
- data/lib/concurrent/event_machine_defer_proxy.rb +23 -23
- data/lib/concurrent/executor.rb +96 -96
- data/lib/concurrent/fixed_thread_pool.rb +99 -99
- data/lib/concurrent/functions.rb +120 -120
- data/lib/concurrent/future.rb +42 -42
- data/lib/concurrent/global_thread_pool.rb +24 -16
- data/lib/concurrent/goroutine.rb +29 -29
- data/lib/concurrent/null_thread_pool.rb +22 -22
- data/lib/concurrent/obligation.rb +67 -67
- data/lib/concurrent/promise.rb +174 -174
- data/lib/concurrent/reactor.rb +166 -166
- data/lib/concurrent/reactor/drb_async_demux.rb +83 -83
- data/lib/concurrent/reactor/tcp_sync_demux.rb +131 -131
- data/lib/concurrent/supervisor.rb +105 -105
- data/lib/concurrent/thread_pool.rb +76 -76
- data/lib/concurrent/utilities.rb +32 -32
- data/lib/concurrent/version.rb +3 -3
- data/lib/concurrent_ruby.rb +1 -1
- data/md/agent.md +123 -123
- data/md/defer.md +174 -174
- data/md/event.md +32 -32
- data/md/executor.md +187 -187
- data/md/future.md +83 -83
- data/md/goroutine.md +52 -52
- data/md/obligation.md +32 -32
- data/md/promise.md +227 -227
- data/md/thread_pool.md +224 -224
- data/spec/concurrent/agent_spec.rb +390 -386
- data/spec/concurrent/cached_thread_pool_spec.rb +125 -125
- data/spec/concurrent/defer_spec.rb +199 -195
- data/spec/concurrent/event_machine_defer_proxy_spec.rb +256 -256
- data/spec/concurrent/event_spec.rb +134 -134
- data/spec/concurrent/executor_spec.rb +200 -200
- data/spec/concurrent/fixed_thread_pool_spec.rb +83 -83
- data/spec/concurrent/functions_spec.rb +217 -217
- data/spec/concurrent/future_spec.rb +112 -108
- data/spec/concurrent/global_thread_pool_spec.rb +11 -38
- data/spec/concurrent/goroutine_spec.rb +67 -67
- data/spec/concurrent/null_thread_pool_spec.rb +57 -57
- data/spec/concurrent/obligation_shared.rb +132 -132
- data/spec/concurrent/promise_spec.rb +316 -312
- data/spec/concurrent/reactor/drb_async_demux_spec.rb +196 -196
- data/spec/concurrent/reactor/tcp_sync_demux_spec.rb +410 -410
- data/spec/concurrent/reactor_spec.rb +364 -364
- data/spec/concurrent/supervisor_spec.rb +269 -269
- data/spec/concurrent/thread_pool_shared.rb +204 -204
- data/spec/concurrent/uses_global_thread_pool_shared.rb +64 -0
- data/spec/concurrent/utilities_spec.rb +74 -74
- data/spec/spec_helper.rb +32 -32
- metadata +17 -19
@@ -1,134 +1,134 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe Event do
|
6
|
-
|
7
|
-
subject{ Event.new }
|
8
|
-
|
9
|
-
context '#initialize' do
|
10
|
-
|
11
|
-
it 'sets the state to unset' do
|
12
|
-
subject.should_not be_set
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
context '#set?' do
|
17
|
-
|
18
|
-
it 'returns true when the event has been set' do
|
19
|
-
subject.set
|
20
|
-
subject.should be_set
|
21
|
-
end
|
22
|
-
|
23
|
-
it 'returns false if the event is unset' do
|
24
|
-
subject.reset
|
25
|
-
subject.should_not be_set
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
context '#set' do
|
30
|
-
|
31
|
-
it 'triggers the event' do
|
32
|
-
subject.reset
|
33
|
-
@expected = false
|
34
|
-
Thread.new{ subject.wait; @expected = true }
|
35
|
-
sleep(0.1)
|
36
|
-
subject.set
|
37
|
-
sleep(0.1)
|
38
|
-
@expected.should be_true
|
39
|
-
end
|
40
|
-
|
41
|
-
it 'sets the state to set' do
|
42
|
-
subject.set
|
43
|
-
subject.should be_set
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
context '#reset' do
|
48
|
-
|
49
|
-
it 'sets the state to unset' do
|
50
|
-
subject.set
|
51
|
-
subject.should be_set
|
52
|
-
subject.reset
|
53
|
-
subject.should_not be_set
|
54
|
-
end
|
55
|
-
end
|
56
|
-
|
57
|
-
context '#pulse' do
|
58
|
-
|
59
|
-
it 'triggers the event' do
|
60
|
-
subject.reset
|
61
|
-
@expected = false
|
62
|
-
Thread.new{ subject.wait; @expected = true }
|
63
|
-
sleep(0.1)
|
64
|
-
subject.pulse
|
65
|
-
sleep(0.1)
|
66
|
-
@expected.should be_true
|
67
|
-
end
|
68
|
-
|
69
|
-
it 'sets the state to unset' do
|
70
|
-
subject.pulse
|
71
|
-
sleep(0.1)
|
72
|
-
subject.should_not be_set
|
73
|
-
end
|
74
|
-
end
|
75
|
-
|
76
|
-
context '#wait' do
|
77
|
-
|
78
|
-
it 'returns immediately when the event has been set' do
|
79
|
-
subject.reset
|
80
|
-
@expected = false
|
81
|
-
subject.set
|
82
|
-
Thread.new{ subject.wait(1000); @expected = true}
|
83
|
-
sleep(1)
|
84
|
-
@expected.should be_true
|
85
|
-
end
|
86
|
-
|
87
|
-
it 'returns true once the event is set' do
|
88
|
-
subject.set
|
89
|
-
subject.wait.should be_true
|
90
|
-
end
|
91
|
-
|
92
|
-
it 'blocks indefinitely when the timer is nil' do
|
93
|
-
subject.reset
|
94
|
-
@expected = false
|
95
|
-
Thread.new{ subject.wait; @expected = true}
|
96
|
-
subject.set
|
97
|
-
sleep(1)
|
98
|
-
@expected.should be_true
|
99
|
-
end
|
100
|
-
|
101
|
-
it 'stops waiting when the timer expires' do
|
102
|
-
subject.reset
|
103
|
-
@expected = false
|
104
|
-
Thread.new{ subject.wait(0.5); @expected = true}
|
105
|
-
sleep(1)
|
106
|
-
@expected.should be_true
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'returns false when the timer expires' do
|
110
|
-
subject.reset
|
111
|
-
subject.wait(1).should be_false
|
112
|
-
end
|
113
|
-
|
114
|
-
it 'triggers multiple waiting threads' do
|
115
|
-
subject.reset
|
116
|
-
@expected = []
|
117
|
-
5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
|
118
|
-
subject.set
|
119
|
-
sleep(1)
|
120
|
-
@expected.length.should eq 5
|
121
|
-
end
|
122
|
-
|
123
|
-
it 'behaves appropriately if wait begins while #set is processing' do
|
124
|
-
subject.reset
|
125
|
-
@expected = []
|
126
|
-
5.times{ Thread.new{ subject.wait(5) } }
|
127
|
-
subject.set
|
128
|
-
5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
|
129
|
-
sleep(1)
|
130
|
-
@expected.length.should eq 5
|
131
|
-
end
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe Event do
|
6
|
+
|
7
|
+
subject{ Event.new }
|
8
|
+
|
9
|
+
context '#initialize' do
|
10
|
+
|
11
|
+
it 'sets the state to unset' do
|
12
|
+
subject.should_not be_set
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context '#set?' do
|
17
|
+
|
18
|
+
it 'returns true when the event has been set' do
|
19
|
+
subject.set
|
20
|
+
subject.should be_set
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns false if the event is unset' do
|
24
|
+
subject.reset
|
25
|
+
subject.should_not be_set
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context '#set' do
|
30
|
+
|
31
|
+
it 'triggers the event' do
|
32
|
+
subject.reset
|
33
|
+
@expected = false
|
34
|
+
Thread.new{ subject.wait; @expected = true }
|
35
|
+
sleep(0.1)
|
36
|
+
subject.set
|
37
|
+
sleep(0.1)
|
38
|
+
@expected.should be_true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'sets the state to set' do
|
42
|
+
subject.set
|
43
|
+
subject.should be_set
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context '#reset' do
|
48
|
+
|
49
|
+
it 'sets the state to unset' do
|
50
|
+
subject.set
|
51
|
+
subject.should be_set
|
52
|
+
subject.reset
|
53
|
+
subject.should_not be_set
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
context '#pulse' do
|
58
|
+
|
59
|
+
it 'triggers the event' do
|
60
|
+
subject.reset
|
61
|
+
@expected = false
|
62
|
+
Thread.new{ subject.wait; @expected = true }
|
63
|
+
sleep(0.1)
|
64
|
+
subject.pulse
|
65
|
+
sleep(0.1)
|
66
|
+
@expected.should be_true
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'sets the state to unset' do
|
70
|
+
subject.pulse
|
71
|
+
sleep(0.1)
|
72
|
+
subject.should_not be_set
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
context '#wait' do
|
77
|
+
|
78
|
+
it 'returns immediately when the event has been set' do
|
79
|
+
subject.reset
|
80
|
+
@expected = false
|
81
|
+
subject.set
|
82
|
+
Thread.new{ subject.wait(1000); @expected = true}
|
83
|
+
sleep(1)
|
84
|
+
@expected.should be_true
|
85
|
+
end
|
86
|
+
|
87
|
+
it 'returns true once the event is set' do
|
88
|
+
subject.set
|
89
|
+
subject.wait.should be_true
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'blocks indefinitely when the timer is nil' do
|
93
|
+
subject.reset
|
94
|
+
@expected = false
|
95
|
+
Thread.new{ subject.wait; @expected = true}
|
96
|
+
subject.set
|
97
|
+
sleep(1)
|
98
|
+
@expected.should be_true
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'stops waiting when the timer expires' do
|
102
|
+
subject.reset
|
103
|
+
@expected = false
|
104
|
+
Thread.new{ subject.wait(0.5); @expected = true}
|
105
|
+
sleep(1)
|
106
|
+
@expected.should be_true
|
107
|
+
end
|
108
|
+
|
109
|
+
it 'returns false when the timer expires' do
|
110
|
+
subject.reset
|
111
|
+
subject.wait(1).should be_false
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'triggers multiple waiting threads' do
|
115
|
+
subject.reset
|
116
|
+
@expected = []
|
117
|
+
5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
|
118
|
+
subject.set
|
119
|
+
sleep(1)
|
120
|
+
@expected.length.should eq 5
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'behaves appropriately if wait begins while #set is processing' do
|
124
|
+
subject.reset
|
125
|
+
@expected = []
|
126
|
+
5.times{ Thread.new{ subject.wait(5) } }
|
127
|
+
subject.set
|
128
|
+
5.times{ Thread.new{ subject.wait; @expected << Thread.current.object_id } }
|
129
|
+
sleep(1)
|
130
|
+
@expected.length.should eq 5
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
@@ -1,200 +1,200 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
module Concurrent
|
4
|
-
|
5
|
-
describe Executor do
|
6
|
-
|
7
|
-
before(:each) do
|
8
|
-
@orig_stdout = $stdout
|
9
|
-
$stdout = StringIO.new
|
10
|
-
end
|
11
|
-
|
12
|
-
after(:each) do
|
13
|
-
$stdout = @orig_stdout
|
14
|
-
end
|
15
|
-
|
16
|
-
after(:each) do
|
17
|
-
@ec.kill unless @ec.nil?
|
18
|
-
end
|
19
|
-
|
20
|
-
context '#run' do
|
21
|
-
|
22
|
-
it 'raises an exception if no block given' do
|
23
|
-
lambda {
|
24
|
-
@ec = Concurrent::Executor.run('Foo')
|
25
|
-
}.should raise_error
|
26
|
-
end
|
27
|
-
|
28
|
-
it 'uses the default execution interval when no interval is given' do
|
29
|
-
@ec = Executor.run('Foo'){ nil }
|
30
|
-
@ec.execution_interval.should eq Executor::EXECUTION_INTERVAL
|
31
|
-
end
|
32
|
-
|
33
|
-
it 'uses the default timeout interval when no interval is given' do
|
34
|
-
@ec = Executor.run('Foo'){ nil }
|
35
|
-
@ec.timeout_interval.should eq Executor::TIMEOUT_INTERVAL
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'uses the given execution interval' do
|
39
|
-
@ec = Executor.run('Foo', execution_interval: 5){ nil }
|
40
|
-
@ec.execution_interval.should eq 5
|
41
|
-
end
|
42
|
-
|
43
|
-
it 'uses the given timeout interval' do
|
44
|
-
@ec = Executor.run('Foo', timeout_interval: 5){ nil }
|
45
|
-
@ec.timeout_interval.should eq 5
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'creates a new thread' do
|
49
|
-
thread = Thread.new{ sleep(1) }
|
50
|
-
Thread.should_receive(:new).with(any_args()).and_return(thread)
|
51
|
-
@ec = Executor.run('Foo'){ nil }
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'returns an ExecutionContext' do
|
55
|
-
@ec = Executor.run('Foo'){ nil }
|
56
|
-
@ec.should be_a(Executor::ExecutionContext)
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'sets the #name context variable' do
|
60
|
-
@ec = Executor.run('Foo'){ nil }
|
61
|
-
@ec.name.should eq 'Foo'
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
context 'execution' do
|
66
|
-
|
67
|
-
it 'runs the block immediately when the :run_now option is true' do
|
68
|
-
@expected = false
|
69
|
-
@ec = Executor.run('Foo', execution: 500, now: true){ @expected = true }
|
70
|
-
@expected.should be_false
|
71
|
-
sleep(1)
|
72
|
-
@expected.should be_true
|
73
|
-
end
|
74
|
-
|
75
|
-
it 'waits for :execution_interval seconds when the :run_now option is false' do
|
76
|
-
@expected = false
|
77
|
-
@ec = Executor.run('Foo', execution: 0.5, now: false){ @expected = true }
|
78
|
-
@expected.should be_false
|
79
|
-
sleep(1)
|
80
|
-
@expected.should be_true
|
81
|
-
end
|
82
|
-
|
83
|
-
it 'waits for :execution_interval seconds when the :run_now option is not given' do
|
84
|
-
@expected = false
|
85
|
-
@ec = Executor.run('Foo', execution: 0.5){ @expected = true }
|
86
|
-
@expected.should be_false
|
87
|
-
sleep(1)
|
88
|
-
@expected.should be_true
|
89
|
-
end
|
90
|
-
|
91
|
-
it 'yields to the execution block' do
|
92
|
-
@expected = false
|
93
|
-
@ec = Executor.run('Foo', execution: 1){ @expected = true }
|
94
|
-
sleep(2)
|
95
|
-
@expected.should be_true
|
96
|
-
end
|
97
|
-
|
98
|
-
it 'passes any given arguments to the execution block' do
|
99
|
-
args = [1,2,3,4]
|
100
|
-
@expected = nil
|
101
|
-
@ec = Executor.run('Foo', execution_interval: 0.5, args: args) do |*args|
|
102
|
-
@expected = args
|
103
|
-
end
|
104
|
-
sleep(1)
|
105
|
-
@expected.should eq args
|
106
|
-
end
|
107
|
-
|
108
|
-
it 'supresses exceptions thrown by the execution block' do
|
109
|
-
lambda {
|
110
|
-
@ec = Executor.run('Foo', execution_interval: 0.5) { raise StandardError }
|
111
|
-
sleep(1)
|
112
|
-
}.should_not raise_error
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'kills the worker thread if the timeout is reached' do
|
116
|
-
# the after(:each) block will trigger this expectation
|
117
|
-
Thread.should_receive(:kill).at_least(1).with(any_args())
|
118
|
-
@ec = Executor.run('Foo', execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
|
119
|
-
sleep(1.5)
|
120
|
-
end
|
121
|
-
end
|
122
|
-
|
123
|
-
context 'logging' do
|
124
|
-
|
125
|
-
before(:each) do
|
126
|
-
@name = nil
|
127
|
-
@level = nil
|
128
|
-
@msg = nil
|
129
|
-
|
130
|
-
@logger = proc do |name, level, msg|
|
131
|
-
@name = name
|
132
|
-
@level = level
|
133
|
-
@msg = msg
|
134
|
-
end
|
135
|
-
end
|
136
|
-
|
137
|
-
it 'uses a custom logger when given' do
|
138
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
|
139
|
-
sleep(0.5)
|
140
|
-
@name.should eq 'Foo'
|
141
|
-
end
|
142
|
-
|
143
|
-
it 'logs :info when execution is successful' do
|
144
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
|
145
|
-
sleep(0.5)
|
146
|
-
@level.should eq :info
|
147
|
-
end
|
148
|
-
|
149
|
-
it 'logs :warn when execution times out' do
|
150
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, timeout_interval: 0.1, logger: @logger){ Thread.stop }
|
151
|
-
sleep(0.5)
|
152
|
-
@level.should eq :warn
|
153
|
-
end
|
154
|
-
|
155
|
-
it 'logs :error when execution is fails' do
|
156
|
-
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ raise StandardError }
|
157
|
-
sleep(0.5)
|
158
|
-
@level.should eq :error
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
context '#status' do
|
163
|
-
|
164
|
-
it 'returns the status of the executor thread when running' do
|
165
|
-
@ec = Executor.run('Foo'){ nil }
|
166
|
-
sleep(0.1)
|
167
|
-
@ec.status.should eq 'sleep'
|
168
|
-
end
|
169
|
-
|
170
|
-
it 'returns nil when not running' do
|
171
|
-
@ec = Executor.run('Foo'){ nil }
|
172
|
-
@ec.kill
|
173
|
-
sleep(0.1)
|
174
|
-
@ec.status.should be_nil
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
context '#join' do
|
179
|
-
|
180
|
-
it 'joins the executor thread when running' do
|
181
|
-
@ec = Executor.run('Foo'){ nil }
|
182
|
-
Thread.new{ sleep(1); @ec.kill }
|
183
|
-
@ec.join.should be_a(Thread)
|
184
|
-
end
|
185
|
-
|
186
|
-
it 'joins the executor thread with timeout when running' do
|
187
|
-
@ec = Executor.run('Foo'){ nil }
|
188
|
-
@ec.join(1).should be_nil
|
189
|
-
end
|
190
|
-
|
191
|
-
it 'immediately returns nil when not running' do
|
192
|
-
@ec = Executor.run('Foo'){ nil }
|
193
|
-
@ec.kill
|
194
|
-
sleep(0.1)
|
195
|
-
@ec.join.should be_nil
|
196
|
-
@ec.join(1).should be_nil
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Concurrent
|
4
|
+
|
5
|
+
describe Executor do
|
6
|
+
|
7
|
+
before(:each) do
|
8
|
+
@orig_stdout = $stdout
|
9
|
+
$stdout = StringIO.new
|
10
|
+
end
|
11
|
+
|
12
|
+
after(:each) do
|
13
|
+
$stdout = @orig_stdout
|
14
|
+
end
|
15
|
+
|
16
|
+
after(:each) do
|
17
|
+
@ec.kill unless @ec.nil?
|
18
|
+
end
|
19
|
+
|
20
|
+
context '#run' do
|
21
|
+
|
22
|
+
it 'raises an exception if no block given' do
|
23
|
+
lambda {
|
24
|
+
@ec = Concurrent::Executor.run('Foo')
|
25
|
+
}.should raise_error
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'uses the default execution interval when no interval is given' do
|
29
|
+
@ec = Executor.run('Foo'){ nil }
|
30
|
+
@ec.execution_interval.should eq Executor::EXECUTION_INTERVAL
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'uses the default timeout interval when no interval is given' do
|
34
|
+
@ec = Executor.run('Foo'){ nil }
|
35
|
+
@ec.timeout_interval.should eq Executor::TIMEOUT_INTERVAL
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'uses the given execution interval' do
|
39
|
+
@ec = Executor.run('Foo', execution_interval: 5){ nil }
|
40
|
+
@ec.execution_interval.should eq 5
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'uses the given timeout interval' do
|
44
|
+
@ec = Executor.run('Foo', timeout_interval: 5){ nil }
|
45
|
+
@ec.timeout_interval.should eq 5
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'creates a new thread' do
|
49
|
+
thread = Thread.new{ sleep(1) }
|
50
|
+
Thread.should_receive(:new).with(any_args()).and_return(thread)
|
51
|
+
@ec = Executor.run('Foo'){ nil }
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'returns an ExecutionContext' do
|
55
|
+
@ec = Executor.run('Foo'){ nil }
|
56
|
+
@ec.should be_a(Executor::ExecutionContext)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'sets the #name context variable' do
|
60
|
+
@ec = Executor.run('Foo'){ nil }
|
61
|
+
@ec.name.should eq 'Foo'
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'execution' do
|
66
|
+
|
67
|
+
it 'runs the block immediately when the :run_now option is true' do
|
68
|
+
@expected = false
|
69
|
+
@ec = Executor.run('Foo', execution: 500, now: true){ @expected = true }
|
70
|
+
@expected.should be_false
|
71
|
+
sleep(1)
|
72
|
+
@expected.should be_true
|
73
|
+
end
|
74
|
+
|
75
|
+
it 'waits for :execution_interval seconds when the :run_now option is false' do
|
76
|
+
@expected = false
|
77
|
+
@ec = Executor.run('Foo', execution: 0.5, now: false){ @expected = true }
|
78
|
+
@expected.should be_false
|
79
|
+
sleep(1)
|
80
|
+
@expected.should be_true
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'waits for :execution_interval seconds when the :run_now option is not given' do
|
84
|
+
@expected = false
|
85
|
+
@ec = Executor.run('Foo', execution: 0.5){ @expected = true }
|
86
|
+
@expected.should be_false
|
87
|
+
sleep(1)
|
88
|
+
@expected.should be_true
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'yields to the execution block' do
|
92
|
+
@expected = false
|
93
|
+
@ec = Executor.run('Foo', execution: 1){ @expected = true }
|
94
|
+
sleep(2)
|
95
|
+
@expected.should be_true
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'passes any given arguments to the execution block' do
|
99
|
+
args = [1,2,3,4]
|
100
|
+
@expected = nil
|
101
|
+
@ec = Executor.run('Foo', execution_interval: 0.5, args: args) do |*args|
|
102
|
+
@expected = args
|
103
|
+
end
|
104
|
+
sleep(1)
|
105
|
+
@expected.should eq args
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'supresses exceptions thrown by the execution block' do
|
109
|
+
lambda {
|
110
|
+
@ec = Executor.run('Foo', execution_interval: 0.5) { raise StandardError }
|
111
|
+
sleep(1)
|
112
|
+
}.should_not raise_error
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'kills the worker thread if the timeout is reached' do
|
116
|
+
# the after(:each) block will trigger this expectation
|
117
|
+
Thread.should_receive(:kill).at_least(1).with(any_args())
|
118
|
+
@ec = Executor.run('Foo', execution_interval: 0.5, timeout_interval: 0.5){ Thread.stop }
|
119
|
+
sleep(1.5)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
context 'logging' do
|
124
|
+
|
125
|
+
before(:each) do
|
126
|
+
@name = nil
|
127
|
+
@level = nil
|
128
|
+
@msg = nil
|
129
|
+
|
130
|
+
@logger = proc do |name, level, msg|
|
131
|
+
@name = name
|
132
|
+
@level = level
|
133
|
+
@msg = msg
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'uses a custom logger when given' do
|
138
|
+
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
|
139
|
+
sleep(0.5)
|
140
|
+
@name.should eq 'Foo'
|
141
|
+
end
|
142
|
+
|
143
|
+
it 'logs :info when execution is successful' do
|
144
|
+
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ nil }
|
145
|
+
sleep(0.5)
|
146
|
+
@level.should eq :info
|
147
|
+
end
|
148
|
+
|
149
|
+
it 'logs :warn when execution times out' do
|
150
|
+
@ec = Executor.run('Foo', execution_interval: 0.1, timeout_interval: 0.1, logger: @logger){ Thread.stop }
|
151
|
+
sleep(0.5)
|
152
|
+
@level.should eq :warn
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'logs :error when execution is fails' do
|
156
|
+
@ec = Executor.run('Foo', execution_interval: 0.1, logger: @logger){ raise StandardError }
|
157
|
+
sleep(0.5)
|
158
|
+
@level.should eq :error
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
162
|
+
context '#status' do
|
163
|
+
|
164
|
+
it 'returns the status of the executor thread when running' do
|
165
|
+
@ec = Executor.run('Foo'){ nil }
|
166
|
+
sleep(0.1)
|
167
|
+
@ec.status.should eq 'sleep'
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'returns nil when not running' do
|
171
|
+
@ec = Executor.run('Foo'){ nil }
|
172
|
+
@ec.kill
|
173
|
+
sleep(0.1)
|
174
|
+
@ec.status.should be_nil
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
context '#join' do
|
179
|
+
|
180
|
+
it 'joins the executor thread when running' do
|
181
|
+
@ec = Executor.run('Foo'){ nil }
|
182
|
+
Thread.new{ sleep(1); @ec.kill }
|
183
|
+
@ec.join.should be_a(Thread)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'joins the executor thread with timeout when running' do
|
187
|
+
@ec = Executor.run('Foo'){ nil }
|
188
|
+
@ec.join(1).should be_nil
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'immediately returns nil when not running' do
|
192
|
+
@ec = Executor.run('Foo'){ nil }
|
193
|
+
@ec.kill
|
194
|
+
sleep(0.1)
|
195
|
+
@ec.join.should be_nil
|
196
|
+
@ec.join(1).should be_nil
|
197
|
+
end
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|