punchblock 0.4.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.
- data/.document +5 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/Gemfile +2 -0
- data/LICENSE.txt +20 -0
- data/README.markdown +31 -0
- data/Rakefile +23 -0
- data/assets/ozone/ask-1.0.xsd +56 -0
- data/assets/ozone/conference-1.0.xsd +17 -0
- data/assets/ozone/ozone-1.0.xsd +127 -0
- data/assets/ozone/say-1.0.xsd +24 -0
- data/assets/ozone/transfer-1.0.xsd +32 -0
- data/bin/punchblock-console +125 -0
- data/lib/punchblock/command/accept.rb +30 -0
- data/lib/punchblock/command/answer.rb +30 -0
- data/lib/punchblock/command/dial.rb +88 -0
- data/lib/punchblock/command/hangup.rb +25 -0
- data/lib/punchblock/command/join.rb +81 -0
- data/lib/punchblock/command/mute.rb +7 -0
- data/lib/punchblock/command/redirect.rb +49 -0
- data/lib/punchblock/command/reject.rb +61 -0
- data/lib/punchblock/command/unjoin.rb +50 -0
- data/lib/punchblock/command/unmute.rb +7 -0
- data/lib/punchblock/command.rb +16 -0
- data/lib/punchblock/command_node.rb +46 -0
- data/lib/punchblock/component/input.rb +320 -0
- data/lib/punchblock/component/output.rb +449 -0
- data/lib/punchblock/component/record.rb +216 -0
- data/lib/punchblock/component/tropo/ask.rb +197 -0
- data/lib/punchblock/component/tropo/conference.rb +328 -0
- data/lib/punchblock/component/tropo/say.rb +113 -0
- data/lib/punchblock/component/tropo/transfer.rb +178 -0
- data/lib/punchblock/component/tropo.rb +12 -0
- data/lib/punchblock/component.rb +73 -0
- data/lib/punchblock/connection.rb +209 -0
- data/lib/punchblock/core_ext/blather/stanza/presence.rb +11 -0
- data/lib/punchblock/core_ext/blather/stanza.rb +26 -0
- data/lib/punchblock/dsl.rb +46 -0
- data/lib/punchblock/event/answered.rb +7 -0
- data/lib/punchblock/event/complete.rb +65 -0
- data/lib/punchblock/event/dtmf.rb +19 -0
- data/lib/punchblock/event/end.rb +15 -0
- data/lib/punchblock/event/info.rb +15 -0
- data/lib/punchblock/event/joined.rb +50 -0
- data/lib/punchblock/event/offer.rb +29 -0
- data/lib/punchblock/event/ringing.rb +7 -0
- data/lib/punchblock/event/unjoined.rb +50 -0
- data/lib/punchblock/event.rb +16 -0
- data/lib/punchblock/generic_connection.rb +18 -0
- data/lib/punchblock/has_headers.rb +34 -0
- data/lib/punchblock/header.rb +47 -0
- data/lib/punchblock/media_container.rb +39 -0
- data/lib/punchblock/media_node.rb +17 -0
- data/lib/punchblock/protocol_error.rb +16 -0
- data/lib/punchblock/rayo_node.rb +88 -0
- data/lib/punchblock/ref.rb +26 -0
- data/lib/punchblock/version.rb +3 -0
- data/lib/punchblock.rb +42 -0
- data/log/.gitkeep +0 -0
- data/punchblock.gemspec +42 -0
- data/spec/punchblock/command/accept_spec.rb +13 -0
- data/spec/punchblock/command/answer_spec.rb +13 -0
- data/spec/punchblock/command/dial_spec.rb +54 -0
- data/spec/punchblock/command/hangup_spec.rb +13 -0
- data/spec/punchblock/command/join_spec.rb +21 -0
- data/spec/punchblock/command/mute_spec.rb +11 -0
- data/spec/punchblock/command/redirect_spec.rb +19 -0
- data/spec/punchblock/command/reject_spec.rb +43 -0
- data/spec/punchblock/command/unjoin_spec.rb +19 -0
- data/spec/punchblock/command/unmute_spec.rb +11 -0
- data/spec/punchblock/command_node_spec.rb +80 -0
- data/spec/punchblock/component/input_spec.rb +188 -0
- data/spec/punchblock/component/output_spec.rb +531 -0
- data/spec/punchblock/component/record_spec.rb +235 -0
- data/spec/punchblock/component/tropo/ask_spec.rb +183 -0
- data/spec/punchblock/component/tropo/conference_spec.rb +360 -0
- data/spec/punchblock/component/tropo/say_spec.rb +171 -0
- data/spec/punchblock/component/tropo/transfer_spec.rb +153 -0
- data/spec/punchblock/component_spec.rb +126 -0
- data/spec/punchblock/connection_spec.rb +194 -0
- data/spec/punchblock/event/answered_spec.rb +23 -0
- data/spec/punchblock/event/complete_spec.rb +80 -0
- data/spec/punchblock/event/dtmf_spec.rb +24 -0
- data/spec/punchblock/event/end_spec.rb +30 -0
- data/spec/punchblock/event/info_spec.rb +30 -0
- data/spec/punchblock/event/joined_spec.rb +32 -0
- data/spec/punchblock/event/offer_spec.rb +35 -0
- data/spec/punchblock/event/ringing_spec.rb +23 -0
- data/spec/punchblock/event/unjoined_spec.rb +32 -0
- data/spec/punchblock/header_spec.rb +44 -0
- data/spec/punchblock/protocol_error_spec.rb +9 -0
- data/spec/punchblock/ref_spec.rb +21 -0
- data/spec/spec_helper.rb +43 -0
- metadata +353 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Component
|
|
5
|
+
module Tropo
|
|
6
|
+
describe Conference do
|
|
7
|
+
it 'registers itself' do
|
|
8
|
+
RayoNode.class_from_registration(:conference, 'urn:xmpp:tropo:conference:1').should == Conference
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "when setting options in initializer" do
|
|
12
|
+
subject do
|
|
13
|
+
Conference.new :name => '1234',
|
|
14
|
+
:terminator => '#',
|
|
15
|
+
:moderator => true,
|
|
16
|
+
:tone_passthrough => true,
|
|
17
|
+
:mute => false,
|
|
18
|
+
:announcement => {:text => "Welcome to Rayo", :voice => 'shelly'},
|
|
19
|
+
:music => {:text => "The moderator how not yet joined.. Listen to this awesome music while you wait.", :voice => 'frank'}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
its(:name) { should == '1234' }
|
|
23
|
+
its(:mute) { should == false }
|
|
24
|
+
its(:terminator) { should == '#' }
|
|
25
|
+
its(:tone_passthrough) { should == true }
|
|
26
|
+
its(:moderator) { should == true }
|
|
27
|
+
its(:announcement) { should == Conference::Announcement.new(:text => "Welcome to Rayo", :voice => 'shelly') }
|
|
28
|
+
its(:music) { should == Conference::Music.new(:text => "The moderator how not yet joined.. Listen to this awesome music while you wait.", :voice => 'frank') }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
its(:mute_status_name) { should == :unknown_mute }
|
|
32
|
+
its(:hold_status_name) { should == :unknown_hold }
|
|
33
|
+
|
|
34
|
+
describe "#==" do
|
|
35
|
+
subject { Conference.new :name => 'the-conference' }
|
|
36
|
+
let(:conference2) { Conference.new :name => 'the-conference' }
|
|
37
|
+
let(:conference3) { Conference.new :name => 'other-conference' }
|
|
38
|
+
|
|
39
|
+
it { should == conference2 }
|
|
40
|
+
it { should_not == conference3 }
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "#transition_state!" do
|
|
44
|
+
describe "with an on-hold" do
|
|
45
|
+
it "should call #onhold!" do
|
|
46
|
+
subject.expects(:onhold!).once
|
|
47
|
+
subject.transition_state! Conference::OnHold.new
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "with an off-hold" do
|
|
52
|
+
it "should call #offhold!" do
|
|
53
|
+
subject.expects(:offhold!).once
|
|
54
|
+
subject.transition_state! Conference::OffHold.new
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end # #transition_state!
|
|
58
|
+
|
|
59
|
+
describe "#requested" do
|
|
60
|
+
context "when requesting to be muted" do
|
|
61
|
+
subject { Conference.new :mute => true }
|
|
62
|
+
before { subject.request! }
|
|
63
|
+
its(:mute_status_name) { should == :muted }
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context "when requesting not to be muted" do
|
|
67
|
+
subject { Conference.new :mute => false }
|
|
68
|
+
before { subject.request! }
|
|
69
|
+
its(:mute_status_name) { should == :unmuted }
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
describe "#onhold!" do
|
|
74
|
+
before do
|
|
75
|
+
subject.onhold!
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
its(:hold_status_name) { should == :onhold }
|
|
79
|
+
|
|
80
|
+
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
81
|
+
lambda { subject.onhold! }.should raise_error(StateMachine::InvalidTransition)
|
|
82
|
+
end
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
describe "#offhold!" do
|
|
86
|
+
before do
|
|
87
|
+
subject.onhold!
|
|
88
|
+
subject.offhold!
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
its(:hold_status_name) { should == :offhold }
|
|
92
|
+
|
|
93
|
+
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
94
|
+
lambda { subject.offhold! }.should raise_error(StateMachine::InvalidTransition)
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
describe "actions" do
|
|
99
|
+
let(:conference) { Conference.new :name => '1234' }
|
|
100
|
+
|
|
101
|
+
before do
|
|
102
|
+
conference.component_id = 'abc123'
|
|
103
|
+
conference.call_id = '123abc'
|
|
104
|
+
conference.connection = Connection.new :username => '123', :password => '123'
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
describe '#mute_action' do
|
|
108
|
+
subject { conference.mute_action }
|
|
109
|
+
|
|
110
|
+
it { should be_a Command::Mute }
|
|
111
|
+
its(:component_id) { should == 'abc123' }
|
|
112
|
+
its(:call_id) { should == '123abc' }
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
describe '#mute!' do
|
|
116
|
+
describe "when unmuted" do
|
|
117
|
+
before do
|
|
118
|
+
conference.request!
|
|
119
|
+
conference.execute!
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
it "should send its command properly" do
|
|
123
|
+
Connection.any_instance.expects(:write).with('123abc', conference.mute_action, 'abc123').returns true
|
|
124
|
+
conference.expects :muted!
|
|
125
|
+
conference.mute!
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
describe "when muted" do
|
|
130
|
+
before { conference.muted! }
|
|
131
|
+
|
|
132
|
+
it "should raise an error" do
|
|
133
|
+
lambda { conference.mute! }.should raise_error(InvalidActionError, "Cannot mute a Conference that is already muted")
|
|
134
|
+
end
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe "#muted!" do
|
|
139
|
+
before do
|
|
140
|
+
subject.request!
|
|
141
|
+
subject.execute!
|
|
142
|
+
subject.muted!
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
its(:mute_status_name) { should == :muted }
|
|
146
|
+
|
|
147
|
+
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
148
|
+
lambda { subject.muted! }.should raise_error(StateMachine::InvalidTransition)
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
describe '#unmute_action' do
|
|
153
|
+
subject { conference.unmute_action }
|
|
154
|
+
|
|
155
|
+
it { should be_a Command::Unmute }
|
|
156
|
+
its(:component_id) { should == 'abc123' }
|
|
157
|
+
its(:call_id) { should == '123abc' }
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
describe '#unmute!' do
|
|
161
|
+
before do
|
|
162
|
+
conference.request!
|
|
163
|
+
conference.execute!
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
describe "when muted" do
|
|
167
|
+
before do
|
|
168
|
+
conference.muted!
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
it "should send its command properly" do
|
|
172
|
+
Connection.any_instance.expects(:write).with('123abc', conference.unmute_action, 'abc123').returns true
|
|
173
|
+
conference.expects :unmuted!
|
|
174
|
+
conference.unmute!
|
|
175
|
+
end
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe "when unmuted" do
|
|
179
|
+
it "should raise an error" do
|
|
180
|
+
lambda { conference.unmute! }.should raise_error(InvalidActionError, "Cannot unmute a Conference that is not muted")
|
|
181
|
+
end
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
describe "#unmuted!" do
|
|
186
|
+
before do
|
|
187
|
+
subject.request!
|
|
188
|
+
subject.execute!
|
|
189
|
+
subject.muted!
|
|
190
|
+
subject.unmuted!
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
its(:mute_status_name) { should == :unmuted }
|
|
194
|
+
|
|
195
|
+
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
196
|
+
lambda { subject.unmuted! }.should raise_error(StateMachine::InvalidTransition)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
describe '#stop_action' do
|
|
201
|
+
subject { conference.stop_action }
|
|
202
|
+
|
|
203
|
+
its(:to_xml) { should == '<stop xmlns="urn:xmpp:rayo:1"/>' }
|
|
204
|
+
its(:component_id) { should == 'abc123' }
|
|
205
|
+
its(:call_id) { should == '123abc' }
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
describe '#stop!' do
|
|
209
|
+
describe "when the command is executing" do
|
|
210
|
+
before do
|
|
211
|
+
conference.request!
|
|
212
|
+
conference.execute!
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
it "should send its command properly" do
|
|
216
|
+
Connection.any_instance.expects(:write).with('123abc', conference.stop_action, 'abc123')
|
|
217
|
+
conference.stop!
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
describe "when the command is not executing" do
|
|
222
|
+
it "should raise an error" do
|
|
223
|
+
lambda { conference.stop! }.should raise_error(InvalidActionError, "Cannot stop a Conference that is not executing")
|
|
224
|
+
end
|
|
225
|
+
end
|
|
226
|
+
end # describe #stop!
|
|
227
|
+
|
|
228
|
+
describe '#kick_action' do
|
|
229
|
+
subject { conference.kick_action :message => 'bye!' }
|
|
230
|
+
|
|
231
|
+
its(:to_xml) { should == '<kick xmlns="urn:xmpp:tropo:conference:1">bye!</kick>' }
|
|
232
|
+
its(:component_id) { should == 'abc123' }
|
|
233
|
+
its(:call_id) { should == '123abc' }
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
describe '#kick!' do
|
|
237
|
+
describe "when the command is executing" do
|
|
238
|
+
before do
|
|
239
|
+
conference.request!
|
|
240
|
+
conference.execute!
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it "should send its command properly" do
|
|
244
|
+
Connection.any_instance.expects(:write).with('123abc', conference.kick_action(:message => 'bye!'), 'abc123')
|
|
245
|
+
conference.kick! :message => 'bye!'
|
|
246
|
+
end
|
|
247
|
+
end
|
|
248
|
+
|
|
249
|
+
describe "when the command is not executing" do
|
|
250
|
+
it "should raise an error" do
|
|
251
|
+
lambda { conference.kick! }.should raise_error(InvalidActionError, "Cannot kick a Conference that is not executing")
|
|
252
|
+
end
|
|
253
|
+
end
|
|
254
|
+
end # describe #kick!
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
describe Conference::OnHold do
|
|
258
|
+
it 'registers itself' do
|
|
259
|
+
RayoNode.class_from_registration(:'on-hold', 'urn:xmpp:tropo:conference:1').should == Conference::OnHold
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
describe "from a stanza" do
|
|
263
|
+
let(:stanza) { "<on-hold xmlns='urn:xmpp:tropo:conference:1'/>" }
|
|
264
|
+
|
|
265
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
266
|
+
|
|
267
|
+
it { should be_instance_of Conference::OnHold }
|
|
268
|
+
|
|
269
|
+
it_should_behave_like 'event'
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
describe Conference::OffHold do
|
|
274
|
+
it 'registers itself' do
|
|
275
|
+
RayoNode.class_from_registration(:'off-hold', 'urn:xmpp:tropo:conference:1').should == Conference::OffHold
|
|
276
|
+
end
|
|
277
|
+
|
|
278
|
+
describe "from a stanza" do
|
|
279
|
+
let(:stanza) { "<off-hold xmlns='urn:xmpp:tropo:conference:1'/>" }
|
|
280
|
+
|
|
281
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
282
|
+
|
|
283
|
+
it { should be_instance_of Conference::OffHold }
|
|
284
|
+
|
|
285
|
+
it_should_behave_like 'event'
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
describe Conference::Speaking do
|
|
290
|
+
it 'registers itself' do
|
|
291
|
+
RayoNode.class_from_registration(:speaking, 'urn:xmpp:tropo:conference:1').should == Conference::Speaking
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
describe "from a stanza" do
|
|
295
|
+
let(:stanza) { "<speaking xmlns='urn:xmpp:tropo:conference:1' call-id='abc123'/>" }
|
|
296
|
+
|
|
297
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
298
|
+
|
|
299
|
+
it { should be_instance_of Conference::Speaking }
|
|
300
|
+
|
|
301
|
+
it_should_behave_like 'event'
|
|
302
|
+
|
|
303
|
+
its(:speaking_call_id) { should == 'abc123' }
|
|
304
|
+
end
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
describe Conference::FinishedSpeaking do
|
|
308
|
+
it 'registers itself' do
|
|
309
|
+
RayoNode.class_from_registration(:'finished-speaking', 'urn:xmpp:tropo:conference:1').should == Conference::FinishedSpeaking
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
describe "from a stanza" do
|
|
313
|
+
let(:stanza) { "<finished-speaking xmlns='urn:xmpp:tropo:conference:1' call-id='abc123'/>" }
|
|
314
|
+
|
|
315
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
316
|
+
|
|
317
|
+
it { should be_instance_of Conference::FinishedSpeaking }
|
|
318
|
+
|
|
319
|
+
it_should_behave_like 'event'
|
|
320
|
+
|
|
321
|
+
its(:speaking_call_id) { should == 'abc123' }
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
describe Conference::Complete::Kick do
|
|
326
|
+
let :stanza do
|
|
327
|
+
<<-MESSAGE
|
|
328
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
329
|
+
<kick xmlns='urn:xmpp:tropo:conference:complete:1'>wouldn't stop talking</kick>
|
|
330
|
+
</complete>
|
|
331
|
+
MESSAGE
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
335
|
+
|
|
336
|
+
it { should be_instance_of Conference::Complete::Kick }
|
|
337
|
+
|
|
338
|
+
its(:name) { should == :kick }
|
|
339
|
+
its(:details) { should == "wouldn't stop talking" }
|
|
340
|
+
end
|
|
341
|
+
|
|
342
|
+
describe Conference::Complete::Terminator do
|
|
343
|
+
let :stanza do
|
|
344
|
+
<<-MESSAGE
|
|
345
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
346
|
+
<terminator xmlns='urn:xmpp:tropo:conference:complete:1' />
|
|
347
|
+
</complete>
|
|
348
|
+
MESSAGE
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
352
|
+
|
|
353
|
+
it { should be_instance_of Conference::Complete::Terminator }
|
|
354
|
+
|
|
355
|
+
its(:name) { should == :terminator }
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
end
|
|
359
|
+
end
|
|
360
|
+
end # Punchblock
|
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Component
|
|
5
|
+
module Tropo
|
|
6
|
+
describe Say do
|
|
7
|
+
it 'registers itself' do
|
|
8
|
+
RayoNode.class_from_registration(:say, 'urn:xmpp:tropo:say:1').should == Say
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe "for text" do
|
|
12
|
+
subject { Say.new :text => 'Once upon a time there was a message...', :voice => 'kate' }
|
|
13
|
+
|
|
14
|
+
its(:voice) { should == 'kate' }
|
|
15
|
+
its(:text) { should == 'Once upon a time there was a message...' }
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "for SSML" do
|
|
19
|
+
subject { Say.new :ssml => '<say-as interpret-as="ordinal">100</say-as>', :voice => 'kate' }
|
|
20
|
+
|
|
21
|
+
its(:voice) { should == 'kate' }
|
|
22
|
+
it "should have the correct content" do
|
|
23
|
+
subject.child.to_s.should == '<say-as interpret-as="ordinal">100</say-as>'
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
describe "actions" do
|
|
28
|
+
let(:command) { Say.new :text => 'Once upon a time there was a message...', :voice => 'kate' }
|
|
29
|
+
|
|
30
|
+
before do
|
|
31
|
+
command.component_id = 'abc123'
|
|
32
|
+
command.call_id = '123abc'
|
|
33
|
+
command.connection = Connection.new :username => '123', :password => '123'
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
describe '#pause_action' do
|
|
37
|
+
subject { command.pause_action }
|
|
38
|
+
|
|
39
|
+
its(:to_xml) { should == '<pause xmlns="urn:xmpp:tropo:say:1"/>' }
|
|
40
|
+
its(:component_id) { should == 'abc123' }
|
|
41
|
+
its(:call_id) { should == '123abc' }
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
describe '#pause!' do
|
|
45
|
+
describe "when the command is executing" do
|
|
46
|
+
before do
|
|
47
|
+
command.request!
|
|
48
|
+
command.execute!
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "should send its command properly" do
|
|
52
|
+
Connection.any_instance.expects(:write).with('123abc', command.pause_action, 'abc123').returns true
|
|
53
|
+
command.expects :paused!
|
|
54
|
+
command.pause!
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
describe "when the command is not executing" do
|
|
59
|
+
it "should raise an error" do
|
|
60
|
+
lambda { command.pause! }.should raise_error(InvalidActionError, "Cannot pause a Say that is not executing")
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe "#paused!" do
|
|
66
|
+
before do
|
|
67
|
+
subject.request!
|
|
68
|
+
subject.execute!
|
|
69
|
+
subject.paused!
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
its(:state_name) { should == :paused }
|
|
73
|
+
|
|
74
|
+
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
75
|
+
lambda { subject.paused! }.should raise_error(StateMachine::InvalidTransition)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
describe '#resume_action' do
|
|
80
|
+
subject { command.resume_action }
|
|
81
|
+
|
|
82
|
+
its(:to_xml) { should == '<resume xmlns="urn:xmpp:tropo:say:1"/>' }
|
|
83
|
+
its(:component_id) { should == 'abc123' }
|
|
84
|
+
its(:call_id) { should == '123abc' }
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe '#resume!' do
|
|
88
|
+
describe "when the command is paused" do
|
|
89
|
+
before do
|
|
90
|
+
command.request!
|
|
91
|
+
command.execute!
|
|
92
|
+
command.paused!
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "should send its command properly" do
|
|
96
|
+
Connection.any_instance.expects(:write).with('123abc', command.resume_action, 'abc123').returns true
|
|
97
|
+
command.expects :resumed!
|
|
98
|
+
command.resume!
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
describe "when the command is not paused" do
|
|
103
|
+
it "should raise an error" do
|
|
104
|
+
lambda { command.resume! }.should raise_error(InvalidActionError, "Cannot resume a Say that is not paused.")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
describe "#resumed!" do
|
|
110
|
+
before do
|
|
111
|
+
subject.request!
|
|
112
|
+
subject.execute!
|
|
113
|
+
subject.paused!
|
|
114
|
+
subject.resumed!
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
its(:state_name) { should == :executing }
|
|
118
|
+
|
|
119
|
+
it "should raise a StateMachine::InvalidTransition when received a second time" do
|
|
120
|
+
lambda { subject.resumed! }.should raise_error(StateMachine::InvalidTransition)
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe '#stop_action' do
|
|
125
|
+
subject { command.stop_action }
|
|
126
|
+
|
|
127
|
+
its(:to_xml) { should == '<stop xmlns="urn:xmpp:rayo:1"/>' }
|
|
128
|
+
its(:component_id) { should == 'abc123' }
|
|
129
|
+
its(:call_id) { should == '123abc' }
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
describe '#stop!' do
|
|
133
|
+
describe "when the command is executing" do
|
|
134
|
+
before do
|
|
135
|
+
command.request!
|
|
136
|
+
command.execute!
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
it "should send its command properly" do
|
|
140
|
+
Connection.any_instance.expects(:write).with('123abc', command.stop_action, 'abc123')
|
|
141
|
+
command.stop!
|
|
142
|
+
end
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
describe "when the command is not executing" do
|
|
146
|
+
it "should raise an error" do
|
|
147
|
+
lambda { command.stop! }.should raise_error(InvalidActionError, "Cannot stop a Say that is not executing")
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end # #stop!
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
describe Say::Complete::Success do
|
|
155
|
+
let :stanza do
|
|
156
|
+
<<-MESSAGE
|
|
157
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
158
|
+
<success xmlns='urn:xmpp:tropo:say:complete:1' />
|
|
159
|
+
</complete>
|
|
160
|
+
MESSAGE
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
164
|
+
|
|
165
|
+
it { should be_instance_of Say::Complete::Success }
|
|
166
|
+
|
|
167
|
+
its(:name) { should == :success }
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
end # Punchblock
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
module Component
|
|
5
|
+
module Tropo
|
|
6
|
+
describe Transfer do
|
|
7
|
+
it 'registers itself' do
|
|
8
|
+
RayoNode.class_from_registration(:transfer, 'urn:xmpp:tropo:transfer:1').should == Transfer
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
describe 'when setting options in initializer' do
|
|
12
|
+
subject do
|
|
13
|
+
Transfer.new :to => 'tel:+14045551212',
|
|
14
|
+
:from => 'tel:+14155551212',
|
|
15
|
+
:terminator => '*',
|
|
16
|
+
:timeout => 120000,
|
|
17
|
+
:answer_on_media => true,
|
|
18
|
+
:media => :direct,
|
|
19
|
+
:ring => {:voice => 'allison', :text => "Welcome to Rayo", :url => "http://it.doesnt.matter.does.it/?"}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
its(:to) { should == %w{tel:+14045551212} }
|
|
23
|
+
its(:from) { should == 'tel:+14155551212' }
|
|
24
|
+
its(:terminator) { should == '*' }
|
|
25
|
+
its(:timeout) { should == 120000 }
|
|
26
|
+
its(:answer_on_media) { should == true }
|
|
27
|
+
its(:media) { should == :direct }
|
|
28
|
+
its(:ring) { should == Transfer::Ring.new(:voice => 'allison', :text => "Welcome to Rayo", :url => "http://it.doesnt.matter.does.it/?") }
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it_should_behave_like 'command_headers'
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe "actions" do
|
|
35
|
+
let(:command) { Transfer.new :to => 'tel:+14045551212', :from => 'tel:+14155551212' }
|
|
36
|
+
|
|
37
|
+
before do
|
|
38
|
+
command.component_id = 'abc123'
|
|
39
|
+
command.call_id = '123abc'
|
|
40
|
+
command.connection = Connection.new :username => '123', :password => '123'
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe '#stop_action' do
|
|
44
|
+
subject { command.stop_action }
|
|
45
|
+
|
|
46
|
+
its(:to_xml) { should == '<stop xmlns="urn:xmpp:rayo:1"/>' }
|
|
47
|
+
its(:component_id) { should == 'abc123' }
|
|
48
|
+
its(:call_id) { should == '123abc' }
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe '#stop!' do
|
|
52
|
+
describe "when the command is executing" do
|
|
53
|
+
before do
|
|
54
|
+
command.request!
|
|
55
|
+
command.execute!
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
it "should send its command properly" do
|
|
59
|
+
Connection.any_instance.expects(:write).with('123abc', command.stop_action, 'abc123')
|
|
60
|
+
command.stop!
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
describe "when the command is not executing" do
|
|
65
|
+
it "should raise an error" do
|
|
66
|
+
lambda { command.stop! }.should raise_error(InvalidActionError, "Cannot stop a Transfer that is not executing")
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
describe Transfer::Complete::Success do
|
|
73
|
+
let :stanza do
|
|
74
|
+
<<-MESSAGE
|
|
75
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
76
|
+
<success xmlns='urn:xmpp:tropo:transfer:complete:1' />
|
|
77
|
+
</complete>
|
|
78
|
+
MESSAGE
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
82
|
+
|
|
83
|
+
it { should be_instance_of Transfer::Complete::Success }
|
|
84
|
+
|
|
85
|
+
its(:name) { should == :success }
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
describe Transfer::Complete::Timeout do
|
|
89
|
+
let :stanza do
|
|
90
|
+
<<-MESSAGE
|
|
91
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
92
|
+
<timeout xmlns='urn:xmpp:tropo:transfer:complete:1' />
|
|
93
|
+
</complete>
|
|
94
|
+
MESSAGE
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
98
|
+
|
|
99
|
+
it { should be_instance_of Transfer::Complete::Timeout }
|
|
100
|
+
|
|
101
|
+
its(:name) { should == :timeout }
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
describe Transfer::Complete::Terminator do
|
|
105
|
+
let :stanza do
|
|
106
|
+
<<-MESSAGE
|
|
107
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
108
|
+
<terminator xmlns='urn:xmpp:tropo:transfer:complete:1' />
|
|
109
|
+
</complete>
|
|
110
|
+
MESSAGE
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
114
|
+
|
|
115
|
+
it { should be_instance_of Transfer::Complete::Terminator }
|
|
116
|
+
|
|
117
|
+
its(:name) { should == :terminator }
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe Transfer::Complete::Busy do
|
|
121
|
+
let :stanza do
|
|
122
|
+
<<-MESSAGE
|
|
123
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
124
|
+
<busy xmlns='urn:xmpp:tropo:transfer:complete:1' />
|
|
125
|
+
</complete>
|
|
126
|
+
MESSAGE
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
130
|
+
|
|
131
|
+
it { should be_instance_of Transfer::Complete::Busy }
|
|
132
|
+
|
|
133
|
+
its(:name) { should == :busy }
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
describe Transfer::Complete::Reject do
|
|
137
|
+
let :stanza do
|
|
138
|
+
<<-MESSAGE
|
|
139
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
140
|
+
<reject xmlns='urn:xmpp:tropo:transfer:complete:1' />
|
|
141
|
+
</complete>
|
|
142
|
+
MESSAGE
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
146
|
+
|
|
147
|
+
it { should be_instance_of Transfer::Complete::Reject }
|
|
148
|
+
|
|
149
|
+
its(:name) { should == :reject }
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end # Punchblock
|