ruby_ami 1.3.4 → 2.0.0
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 +4 -4
- data/.travis.yml +1 -0
- data/CHANGELOG.md +5 -2
- data/README.md +14 -15
- data/features/support/lexer_helper.rb +18 -0
- data/lib/ruby_ami/action.rb +19 -65
- data/lib/ruby_ami/agi_result_parser.rb +2 -2
- data/lib/ruby_ami/client.rb +28 -159
- data/lib/ruby_ami/error.rb +2 -2
- data/lib/ruby_ami/event.rb +2 -2
- data/lib/ruby_ami/response.rb +6 -8
- data/lib/ruby_ami/stream.rb +76 -11
- data/lib/ruby_ami/version.rb +1 -1
- data/lib/ruby_ami.rb +0 -9
- data/ruby_ami.gemspec +0 -4
- data/spec/ruby_ami/action_spec.rb +27 -78
- data/spec/ruby_ami/agi_result_parser_spec.rb +0 -9
- data/spec/ruby_ami/client_spec.rb +17 -287
- data/spec/ruby_ami/event_spec.rb +24 -30
- data/spec/ruby_ami/response_spec.rb +12 -20
- data/spec/ruby_ami/stream_spec.rb +142 -49
- data/spec/spec_helper.rb +2 -3
- data/spec/support/mock_server.rb +0 -4
- metadata +2 -59
- data/lib/ruby_ami/metaprogramming.rb +0 -18
@@ -19,13 +19,11 @@ module RubyAMI
|
|
19
19
|
|
20
20
|
it { should be_stopped }
|
21
21
|
|
22
|
-
its(:
|
23
|
-
|
24
|
-
its(:action_queue) { should be_a GirlFriday::WorkQueue }
|
25
|
-
|
26
|
-
its(:streams) { should == [] }
|
22
|
+
its(:events_stream) { should be_a Stream }
|
23
|
+
its(:actions_stream) { should be_a Stream }
|
27
24
|
|
28
25
|
it 'should return when the timeout option is specified and reached' do
|
26
|
+
pending
|
29
27
|
options[:timeout] = 2
|
30
28
|
options[:host] = '192.0.2.1' # unreachable IP that will generally cause a timeout (RFC 5737)
|
31
29
|
|
@@ -39,99 +37,44 @@ module RubyAMI
|
|
39
37
|
describe 'starting up' do
|
40
38
|
before do
|
41
39
|
ms = MockServer.new
|
42
|
-
ms.
|
40
|
+
ms.should_receive(:receive_data).at_least :once
|
43
41
|
s = ServerMock.new options[:host], options[:port], ms
|
44
|
-
|
42
|
+
subject.async.start
|
45
43
|
sleep 0.2
|
46
44
|
end
|
47
45
|
|
48
46
|
it { should be_started }
|
49
|
-
|
50
|
-
its(:events_stream) { should be_a Stream }
|
51
|
-
its(:actions_stream) { should be_a Stream }
|
52
47
|
end
|
53
48
|
|
54
49
|
describe 'logging in streams' do
|
55
50
|
context 'when the actions stream connects' do
|
56
51
|
let(:mock_actions_stream) { mock 'Actions Stream' }
|
57
52
|
|
58
|
-
let :expected_login_action do
|
59
|
-
Action.new 'Login',
|
60
|
-
'Username' => 'username',
|
61
|
-
'Secret' => 'password',
|
62
|
-
'Events' => 'On'
|
63
|
-
end
|
64
|
-
|
65
53
|
before do
|
66
|
-
|
67
|
-
subject.stubs(:actions_stream).returns mock_actions_stream
|
54
|
+
subject.wrapped_object.stub(:actions_stream).and_return mock_actions_stream
|
68
55
|
end
|
69
56
|
|
70
|
-
it 'should
|
71
|
-
mock_actions_stream.
|
72
|
-
action.to_s.should == expected_login_action.to_s
|
73
|
-
end
|
57
|
+
it 'should disable events' do
|
58
|
+
mock_actions_stream.should_receive(:send_action).with 'Events', 'EventMask' => 'Off'
|
74
59
|
|
75
|
-
subject.handle_message
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
context 'when the events stream connects' do
|
80
|
-
let(:mock_events_stream) { mock 'Events Stream' }
|
81
|
-
|
82
|
-
let :expected_login_action do
|
83
|
-
Action.new 'Login',
|
84
|
-
'Username' => 'username',
|
85
|
-
'Secret' => 'password',
|
86
|
-
'Events' => 'On'
|
87
|
-
end
|
88
|
-
|
89
|
-
before do
|
90
|
-
subject.stubs(:events_stream).returns mock_events_stream
|
91
|
-
end
|
92
|
-
|
93
|
-
it 'should log in' do
|
94
|
-
mock_events_stream.expects(:send_action).with expected_login_action
|
95
|
-
|
96
|
-
subject.handle_event Stream::Connected.new
|
97
|
-
|
98
|
-
event_handler.should be_empty
|
60
|
+
subject.handle_message Stream::Connected.new
|
99
61
|
end
|
100
62
|
end
|
101
63
|
end
|
102
64
|
|
103
65
|
describe 'when the events stream disconnects' do
|
104
|
-
it 'should
|
105
|
-
subject.
|
106
|
-
|
107
|
-
|
66
|
+
it 'should shut down the client' do
|
67
|
+
subject.events_stream.terminate
|
68
|
+
sleep 0.2
|
69
|
+
subject.should_not be_alive
|
108
70
|
end
|
109
71
|
end
|
110
72
|
|
111
73
|
describe 'when the actions stream disconnects' do
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
it 'should prevent further actions being sent' do
|
117
|
-
subject.expects(:_send_action).once
|
118
|
-
|
119
|
-
GirlFriday::WorkQueue.immediate!
|
120
|
-
subject.handle_message Stream::Connected.new
|
121
|
-
GirlFriday::WorkQueue.queue!
|
122
|
-
subject.handle_message Stream::Disconnected.new
|
123
|
-
|
124
|
-
action = Action.new 'foo'
|
125
|
-
subject.send_action action
|
126
|
-
|
127
|
-
sleep 2
|
128
|
-
|
129
|
-
action.should be_new
|
130
|
-
end
|
131
|
-
|
132
|
-
it 'should stop' do
|
133
|
-
subject.expects(:stop).once
|
134
|
-
subject.handle_message Stream::Disconnected.new
|
74
|
+
it 'should shut down the client' do
|
75
|
+
subject.actions_stream.terminate
|
76
|
+
sleep 0.2
|
77
|
+
subject.should_not be_alive
|
135
78
|
end
|
136
79
|
end
|
137
80
|
|
@@ -143,218 +86,5 @@ module RubyAMI
|
|
143
86
|
event_handler.should == [event]
|
144
87
|
end
|
145
88
|
end
|
146
|
-
|
147
|
-
describe 'when a FullyBooted event is received on the actions connection' do
|
148
|
-
let(:event) { Event.new 'FullyBooted' }
|
149
|
-
|
150
|
-
let(:mock_actions_stream) { mock 'Actions Stream' }
|
151
|
-
|
152
|
-
let :expected_login_action do
|
153
|
-
Action.new 'Login',
|
154
|
-
'Username' => 'username',
|
155
|
-
'Secret' => 'password',
|
156
|
-
'Events' => 'On'
|
157
|
-
end
|
158
|
-
|
159
|
-
let :expected_events_off_action do
|
160
|
-
Action.new 'Events', 'EventMask' => 'Off'
|
161
|
-
end
|
162
|
-
|
163
|
-
it 'should call the event handler' do
|
164
|
-
subject.handle_message event
|
165
|
-
event_handler.should == [event]
|
166
|
-
end
|
167
|
-
|
168
|
-
it 'should begin writing actions' do
|
169
|
-
subject.expects(:start_writing_actions).once
|
170
|
-
subject.handle_message event
|
171
|
-
end
|
172
|
-
|
173
|
-
it 'should turn off events' do
|
174
|
-
Action.any_instance.stubs(:response).returns true
|
175
|
-
subject.stubs(:actions_stream).returns mock_actions_stream
|
176
|
-
|
177
|
-
mock_actions_stream.expects(:send_action).once.with expected_login_action
|
178
|
-
mock_actions_stream.expects(:send_action).once.with expected_events_off_action
|
179
|
-
|
180
|
-
login_action = subject.handle_message(Stream::Connected.new).join
|
181
|
-
login_action.value.response = true
|
182
|
-
|
183
|
-
subject.handle_message event
|
184
|
-
sleep 0.5
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
|
-
describe 'sending actions' do
|
189
|
-
let(:action_name) { 'Login' }
|
190
|
-
let :headers do
|
191
|
-
{
|
192
|
-
'Username' => 'username',
|
193
|
-
'Secret' => 'password'
|
194
|
-
}
|
195
|
-
end
|
196
|
-
let(:expected_action) { Action.new action_name, headers }
|
197
|
-
|
198
|
-
let :expected_response do
|
199
|
-
Response.new.tap do |response|
|
200
|
-
response['ActionID'] = expected_action.action_id
|
201
|
-
response['Message'] = 'Action completed'
|
202
|
-
end
|
203
|
-
end
|
204
|
-
|
205
|
-
let(:mock_actions_stream) { mock 'Actions Stream' }
|
206
|
-
|
207
|
-
before do
|
208
|
-
subject.stubs(:actions_stream).returns mock_actions_stream
|
209
|
-
subject.stubs(:login_actions).returns nil
|
210
|
-
end
|
211
|
-
|
212
|
-
it 'should queue up actions to be sent' do
|
213
|
-
subject.handle_message Stream::Connected.new
|
214
|
-
subject.action_queue.expects(:<<).with expected_action
|
215
|
-
subject.send_action action_name, headers
|
216
|
-
end
|
217
|
-
|
218
|
-
describe 'forcibly for testing' do
|
219
|
-
before do
|
220
|
-
subject.actions_stream.expects(:send_action).with expected_action
|
221
|
-
subject._send_action expected_action
|
222
|
-
end
|
223
|
-
|
224
|
-
it 'should mark the action sent' do
|
225
|
-
expected_action.should be_sent
|
226
|
-
end
|
227
|
-
|
228
|
-
let(:receive_response) { subject.handle_message expected_response }
|
229
|
-
|
230
|
-
describe 'when a response is received' do
|
231
|
-
it 'should be sent to the action' do
|
232
|
-
expected_action.expects(:<<).once.with expected_response
|
233
|
-
receive_response
|
234
|
-
end
|
235
|
-
|
236
|
-
it 'should know its action' do
|
237
|
-
receive_response
|
238
|
-
expected_response.action.should be expected_action
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
describe 'when an error is received' do
|
243
|
-
let :expected_response do
|
244
|
-
Error.new.tap do |response|
|
245
|
-
response['ActionID'] = expected_action.action_id
|
246
|
-
response['Message'] = 'Action failed'
|
247
|
-
end
|
248
|
-
end
|
249
|
-
|
250
|
-
it 'should be sent to the action' do
|
251
|
-
expected_action.expects(:<<).once.with expected_response
|
252
|
-
receive_response
|
253
|
-
end
|
254
|
-
|
255
|
-
it 'should know its action' do
|
256
|
-
receive_response
|
257
|
-
expected_response.action.should be expected_action
|
258
|
-
end
|
259
|
-
end
|
260
|
-
|
261
|
-
describe 'when an event is received' do
|
262
|
-
let(:event) { Event.new 'foo' }
|
263
|
-
|
264
|
-
let(:receive_event) { subject.handle_message event }
|
265
|
-
|
266
|
-
context 'for a causal event' do
|
267
|
-
let(:expected_action) { Action.new 'Status' }
|
268
|
-
|
269
|
-
it 'should be sent to the action' do
|
270
|
-
expected_action.expects(:<<).once.with expected_response
|
271
|
-
expected_action.expects(:<<).once.with event
|
272
|
-
receive_response
|
273
|
-
receive_event
|
274
|
-
end
|
275
|
-
|
276
|
-
it 'should know its action' do
|
277
|
-
expected_action.stubs :<<
|
278
|
-
receive_response
|
279
|
-
receive_event
|
280
|
-
event.action.should be expected_action
|
281
|
-
end
|
282
|
-
end
|
283
|
-
|
284
|
-
context 'for a causal action which is complete' do
|
285
|
-
let(:expected_action) { Action.new 'Status' }
|
286
|
-
|
287
|
-
before do
|
288
|
-
expected_action.stubs(:complete?).returns true
|
289
|
-
end
|
290
|
-
|
291
|
-
it 'should raise an error' do
|
292
|
-
receive_response
|
293
|
-
receive_event
|
294
|
-
lambda { subject.handle_message Event.new('bar') }.should raise_error StandardError, /causal action/
|
295
|
-
end
|
296
|
-
end
|
297
|
-
|
298
|
-
context 'for a non-causal action' do
|
299
|
-
it 'should raise an error' do
|
300
|
-
lambda { receive_event }.should raise_error StandardError, /causal action/
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
describe 'from the queue' do
|
307
|
-
it 'should send actions to the stream and set their responses' do
|
308
|
-
subject.actions_stream.expects(:send_action).with expected_action
|
309
|
-
subject.handle_message Event.new('FullyBooted')
|
310
|
-
|
311
|
-
Thread.new do
|
312
|
-
GirlFriday::WorkQueue.immediate!
|
313
|
-
subject.send_action expected_action
|
314
|
-
GirlFriday::WorkQueue.queue!
|
315
|
-
end
|
316
|
-
|
317
|
-
sleep 0.1
|
318
|
-
|
319
|
-
subject.handle_message expected_response
|
320
|
-
expected_action.response.should be expected_response
|
321
|
-
end
|
322
|
-
|
323
|
-
it 'should not send another action if the first action has not yet received a response' do
|
324
|
-
subject.actions_stream.expects(:send_action).once.with expected_action
|
325
|
-
subject.handle_message Event.new('FullyBooted')
|
326
|
-
actions = []
|
327
|
-
|
328
|
-
2.times do
|
329
|
-
action = Action.new action_name, headers
|
330
|
-
actions << action
|
331
|
-
subject.send_action action
|
332
|
-
end
|
333
|
-
|
334
|
-
sleep 2
|
335
|
-
|
336
|
-
actions.should have(2).actions
|
337
|
-
actions[0].should be_sent
|
338
|
-
actions[1].should be_new
|
339
|
-
end
|
340
|
-
end
|
341
|
-
end
|
342
|
-
|
343
|
-
describe '#stop' do
|
344
|
-
let(:mock_actions_stream) { mock 'Actions Stream', :alive? => true }
|
345
|
-
let(:mock_events_stream) { mock 'Events Stream', :alive? => true }
|
346
|
-
|
347
|
-
let(:streams) { [mock_actions_stream, mock_events_stream] }
|
348
|
-
|
349
|
-
before do
|
350
|
-
subject.stubs(:actions_stream).returns mock_actions_stream
|
351
|
-
subject.stubs(:events_stream).returns mock_events_stream
|
352
|
-
end
|
353
|
-
|
354
|
-
it 'should close both streams' do
|
355
|
-
streams.each { |s| s.expects :terminate }
|
356
|
-
subject.stop
|
357
|
-
end
|
358
|
-
end
|
359
89
|
end
|
360
90
|
end
|
data/spec/ruby_ami/event_spec.rb
CHANGED
@@ -6,19 +6,17 @@ module RubyAMI
|
|
6
6
|
describe "equality" do
|
7
7
|
context "with the same name and the same headers" do
|
8
8
|
let :event1 do
|
9
|
-
Event.new
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
end
|
9
|
+
Event.new 'Hangup',
|
10
|
+
'Channel' => 'SIP/101-3f3f',
|
11
|
+
'Uniqueid' => '1094154427.10',
|
12
|
+
'Cause' => '0'
|
14
13
|
end
|
15
14
|
|
16
15
|
let :event2 do
|
17
|
-
Event.new
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
end
|
16
|
+
Event.new 'Hangup',
|
17
|
+
'Channel' => 'SIP/101-3f3f',
|
18
|
+
'Uniqueid' => '1094154427.10',
|
19
|
+
'Cause' => '0'
|
22
20
|
end
|
23
21
|
|
24
22
|
it "should be equal" do
|
@@ -28,19 +26,17 @@ module RubyAMI
|
|
28
26
|
|
29
27
|
context "with a different name and the same headers" do
|
30
28
|
let :event1 do
|
31
|
-
Event.new
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
end
|
29
|
+
Event.new 'Hangup',
|
30
|
+
'Channel' => 'SIP/101-3f3f',
|
31
|
+
'Uniqueid' => '1094154427.10',
|
32
|
+
'Cause' => '0'
|
36
33
|
end
|
37
34
|
|
38
35
|
let :event2 do
|
39
|
-
Event.new
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
end
|
36
|
+
Event.new 'Foo',
|
37
|
+
'Channel' => 'SIP/101-3f3f',
|
38
|
+
'Uniqueid' => '1094154427.10',
|
39
|
+
'Cause' => '0'
|
44
40
|
end
|
45
41
|
|
46
42
|
it "should not be equal" do
|
@@ -50,19 +46,17 @@ module RubyAMI
|
|
50
46
|
|
51
47
|
context "with the same name and different headers" do
|
52
48
|
let :event1 do
|
53
|
-
Event.new
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
end
|
49
|
+
Event.new 'Hangup',
|
50
|
+
'Channel' => 'SIP/101-3f3f',
|
51
|
+
'Uniqueid' => '1094154427.10',
|
52
|
+
'Cause' => '0'
|
58
53
|
end
|
59
54
|
|
60
55
|
let :event2 do
|
61
|
-
Event.new
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
end
|
56
|
+
Event.new 'Hangup',
|
57
|
+
'Channel' => 'SIP/101-3f3f',
|
58
|
+
'Uniqueid' => '1094154427.10',
|
59
|
+
'Cause' => '1'
|
66
60
|
end
|
67
61
|
|
68
62
|
it "should not be equal" do
|
@@ -6,19 +6,15 @@ module RubyAMI
|
|
6
6
|
describe "equality" do
|
7
7
|
context "with the same headers" do
|
8
8
|
let :event1 do
|
9
|
-
Response.new
|
10
|
-
|
11
|
-
|
12
|
-
e['Cause'] = '0'
|
13
|
-
end
|
9
|
+
Response.new 'Channel' => 'SIP/101-3f3f',
|
10
|
+
'Uniqueid' => '1094154427.10',
|
11
|
+
'Cause' => '0'
|
14
12
|
end
|
15
13
|
|
16
14
|
let :event2 do
|
17
|
-
Response.new
|
18
|
-
|
19
|
-
|
20
|
-
e['Cause'] = '0'
|
21
|
-
end
|
15
|
+
Response.new 'Channel' => 'SIP/101-3f3f',
|
16
|
+
'Uniqueid' => '1094154427.10',
|
17
|
+
'Cause' => '0'
|
22
18
|
end
|
23
19
|
|
24
20
|
it "should be equal" do
|
@@ -28,19 +24,15 @@ module RubyAMI
|
|
28
24
|
|
29
25
|
context "with different headers" do
|
30
26
|
let :event1 do
|
31
|
-
Response.new
|
32
|
-
|
33
|
-
|
34
|
-
e['Cause'] = '0'
|
35
|
-
end
|
27
|
+
Response.new 'Channel' => 'SIP/101-3f3f',
|
28
|
+
'Uniqueid' => '1094154427.10',
|
29
|
+
'Cause' => '0'
|
36
30
|
end
|
37
31
|
|
38
32
|
let :event2 do
|
39
|
-
Response.new
|
40
|
-
|
41
|
-
|
42
|
-
e['Cause'] = '1'
|
43
|
-
end
|
33
|
+
Response.new 'Channel' => 'SIP/101-3f3f',
|
34
|
+
'Uniqueid' => '1094154427.10',
|
35
|
+
'Cause' => '1'
|
44
36
|
end
|
45
37
|
|
46
38
|
it "should not be equal" do
|