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.
Files changed (94) hide show
  1. data/.document +5 -0
  2. data/.gitignore +12 -0
  3. data/.rspec +3 -0
  4. data/Gemfile +2 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.markdown +31 -0
  7. data/Rakefile +23 -0
  8. data/assets/ozone/ask-1.0.xsd +56 -0
  9. data/assets/ozone/conference-1.0.xsd +17 -0
  10. data/assets/ozone/ozone-1.0.xsd +127 -0
  11. data/assets/ozone/say-1.0.xsd +24 -0
  12. data/assets/ozone/transfer-1.0.xsd +32 -0
  13. data/bin/punchblock-console +125 -0
  14. data/lib/punchblock/command/accept.rb +30 -0
  15. data/lib/punchblock/command/answer.rb +30 -0
  16. data/lib/punchblock/command/dial.rb +88 -0
  17. data/lib/punchblock/command/hangup.rb +25 -0
  18. data/lib/punchblock/command/join.rb +81 -0
  19. data/lib/punchblock/command/mute.rb +7 -0
  20. data/lib/punchblock/command/redirect.rb +49 -0
  21. data/lib/punchblock/command/reject.rb +61 -0
  22. data/lib/punchblock/command/unjoin.rb +50 -0
  23. data/lib/punchblock/command/unmute.rb +7 -0
  24. data/lib/punchblock/command.rb +16 -0
  25. data/lib/punchblock/command_node.rb +46 -0
  26. data/lib/punchblock/component/input.rb +320 -0
  27. data/lib/punchblock/component/output.rb +449 -0
  28. data/lib/punchblock/component/record.rb +216 -0
  29. data/lib/punchblock/component/tropo/ask.rb +197 -0
  30. data/lib/punchblock/component/tropo/conference.rb +328 -0
  31. data/lib/punchblock/component/tropo/say.rb +113 -0
  32. data/lib/punchblock/component/tropo/transfer.rb +178 -0
  33. data/lib/punchblock/component/tropo.rb +12 -0
  34. data/lib/punchblock/component.rb +73 -0
  35. data/lib/punchblock/connection.rb +209 -0
  36. data/lib/punchblock/core_ext/blather/stanza/presence.rb +11 -0
  37. data/lib/punchblock/core_ext/blather/stanza.rb +26 -0
  38. data/lib/punchblock/dsl.rb +46 -0
  39. data/lib/punchblock/event/answered.rb +7 -0
  40. data/lib/punchblock/event/complete.rb +65 -0
  41. data/lib/punchblock/event/dtmf.rb +19 -0
  42. data/lib/punchblock/event/end.rb +15 -0
  43. data/lib/punchblock/event/info.rb +15 -0
  44. data/lib/punchblock/event/joined.rb +50 -0
  45. data/lib/punchblock/event/offer.rb +29 -0
  46. data/lib/punchblock/event/ringing.rb +7 -0
  47. data/lib/punchblock/event/unjoined.rb +50 -0
  48. data/lib/punchblock/event.rb +16 -0
  49. data/lib/punchblock/generic_connection.rb +18 -0
  50. data/lib/punchblock/has_headers.rb +34 -0
  51. data/lib/punchblock/header.rb +47 -0
  52. data/lib/punchblock/media_container.rb +39 -0
  53. data/lib/punchblock/media_node.rb +17 -0
  54. data/lib/punchblock/protocol_error.rb +16 -0
  55. data/lib/punchblock/rayo_node.rb +88 -0
  56. data/lib/punchblock/ref.rb +26 -0
  57. data/lib/punchblock/version.rb +3 -0
  58. data/lib/punchblock.rb +42 -0
  59. data/log/.gitkeep +0 -0
  60. data/punchblock.gemspec +42 -0
  61. data/spec/punchblock/command/accept_spec.rb +13 -0
  62. data/spec/punchblock/command/answer_spec.rb +13 -0
  63. data/spec/punchblock/command/dial_spec.rb +54 -0
  64. data/spec/punchblock/command/hangup_spec.rb +13 -0
  65. data/spec/punchblock/command/join_spec.rb +21 -0
  66. data/spec/punchblock/command/mute_spec.rb +11 -0
  67. data/spec/punchblock/command/redirect_spec.rb +19 -0
  68. data/spec/punchblock/command/reject_spec.rb +43 -0
  69. data/spec/punchblock/command/unjoin_spec.rb +19 -0
  70. data/spec/punchblock/command/unmute_spec.rb +11 -0
  71. data/spec/punchblock/command_node_spec.rb +80 -0
  72. data/spec/punchblock/component/input_spec.rb +188 -0
  73. data/spec/punchblock/component/output_spec.rb +531 -0
  74. data/spec/punchblock/component/record_spec.rb +235 -0
  75. data/spec/punchblock/component/tropo/ask_spec.rb +183 -0
  76. data/spec/punchblock/component/tropo/conference_spec.rb +360 -0
  77. data/spec/punchblock/component/tropo/say_spec.rb +171 -0
  78. data/spec/punchblock/component/tropo/transfer_spec.rb +153 -0
  79. data/spec/punchblock/component_spec.rb +126 -0
  80. data/spec/punchblock/connection_spec.rb +194 -0
  81. data/spec/punchblock/event/answered_spec.rb +23 -0
  82. data/spec/punchblock/event/complete_spec.rb +80 -0
  83. data/spec/punchblock/event/dtmf_spec.rb +24 -0
  84. data/spec/punchblock/event/end_spec.rb +30 -0
  85. data/spec/punchblock/event/info_spec.rb +30 -0
  86. data/spec/punchblock/event/joined_spec.rb +32 -0
  87. data/spec/punchblock/event/offer_spec.rb +35 -0
  88. data/spec/punchblock/event/ringing_spec.rb +23 -0
  89. data/spec/punchblock/event/unjoined_spec.rb +32 -0
  90. data/spec/punchblock/header_spec.rb +44 -0
  91. data/spec/punchblock/protocol_error_spec.rb +9 -0
  92. data/spec/punchblock/ref_spec.rb +21 -0
  93. data/spec/spec_helper.rb +43 -0
  94. metadata +353 -0
@@ -0,0 +1,531 @@
1
+ require 'spec_helper'
2
+
3
+ module Punchblock
4
+ module Component
5
+ describe Output do
6
+ it 'registers itself' do
7
+ RayoNode.class_from_registration(:output, 'urn:xmpp:rayo:output:1').should == Output
8
+ end
9
+
10
+ describe "when setting options in initializer" do
11
+ subject do
12
+ Output.new :interrupt_on => :speech,
13
+ :start_offset => 2000,
14
+ :start_paused => false,
15
+ :repeat_interval => 2000,
16
+ :repeat_times => 10,
17
+ :max_time => 30000,
18
+ :voice => 'allison'
19
+ end
20
+
21
+ its(:interrupt_on) { should == :speech }
22
+ its(:start_offset) { should == 2000 }
23
+ its(:start_paused) { should == false }
24
+ its(:repeat_interval) { should == 2000 }
25
+ its(:repeat_times) { should == 10 }
26
+ its(:max_time) { should == 30000 }
27
+ its(:voice) { should == 'allison' }
28
+ end
29
+
30
+ describe "for text" do
31
+ subject { Output.new :text => 'Once upon a time there was a message...', :voice => 'kate' }
32
+
33
+ its(:voice) { should == 'kate' }
34
+ its(:text) { should == 'Once upon a time there was a message...' }
35
+ end
36
+
37
+ describe "for SSML" do
38
+ subject { Output.new :ssml => '<output-as interpret-as="ordinal">100</output-as>', :voice => 'kate' }
39
+
40
+ its(:voice) { should == 'kate' }
41
+
42
+ its(:ssml) { should == '<output-as interpret-as="ordinal">100</output-as>' }
43
+
44
+ describe "comparison" do
45
+ let(:output2) { Output.new :ssml => '<output-as interpret-as="ordinal">100</output-as>', :voice => 'kate' }
46
+ let(:output3) { Output.new :ssml => '<output-as interpret-as="number">100</output-as>', :voice => 'kate' }
47
+
48
+ it { should == output2 }
49
+ it { should_not == output3 }
50
+ end
51
+ end
52
+
53
+ describe "actions" do
54
+ let(:command) { Output.new :text => 'Once upon a time there was a message...', :voice => 'kate' }
55
+
56
+ before do
57
+ command.component_id = 'abc123'
58
+ command.call_id = '123abc'
59
+ command.connection = Connection.new :username => '123', :password => '123'
60
+ end
61
+
62
+ describe '#pause_action' do
63
+ subject { command.pause_action }
64
+
65
+ its(:to_xml) { should == '<pause xmlns="urn:xmpp:rayo:output:1"/>' }
66
+ its(:component_id) { should == 'abc123' }
67
+ its(:call_id) { should == '123abc' }
68
+ end
69
+
70
+ describe '#pause!' do
71
+ describe "when the command is executing" do
72
+ before do
73
+ command.request!
74
+ command.execute!
75
+ end
76
+
77
+ it "should send its command properly" do
78
+ Connection.any_instance.expects(:write).with('123abc', command.pause_action, 'abc123').returns true
79
+ command.expects :paused!
80
+ command.pause!
81
+ end
82
+ end
83
+
84
+ describe "when the command is not executing" do
85
+ it "should raise an error" do
86
+ lambda { command.pause! }.should raise_error(InvalidActionError, "Cannot pause a Output that is not executing")
87
+ end
88
+ end
89
+ end
90
+
91
+ describe "#paused!" do
92
+ before do
93
+ subject.request!
94
+ subject.execute!
95
+ subject.paused!
96
+ end
97
+
98
+ its(:state_name) { should == :paused }
99
+
100
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
101
+ lambda { subject.paused! }.should raise_error(StateMachine::InvalidTransition)
102
+ end
103
+ end
104
+
105
+ describe '#resume_action' do
106
+ subject { command.resume_action }
107
+
108
+ its(:to_xml) { should == '<resume xmlns="urn:xmpp:rayo:output:1"/>' }
109
+ its(:component_id) { should == 'abc123' }
110
+ its(:call_id) { should == '123abc' }
111
+ end
112
+
113
+ describe '#resume!' do
114
+ describe "when the command is paused" do
115
+ before do
116
+ command.request!
117
+ command.execute!
118
+ command.paused!
119
+ end
120
+
121
+ it "should send its command properly" do
122
+ Connection.any_instance.expects(:write).with('123abc', command.resume_action, 'abc123').returns true
123
+ command.expects :resumed!
124
+ command.resume!
125
+ end
126
+ end
127
+
128
+ describe "when the command is not paused" do
129
+ it "should raise an error" do
130
+ lambda { command.resume! }.should raise_error(InvalidActionError, "Cannot resume a Output that is not paused.")
131
+ end
132
+ end
133
+ end
134
+
135
+ describe "#resumed!" do
136
+ before do
137
+ subject.request!
138
+ subject.execute!
139
+ subject.paused!
140
+ subject.resumed!
141
+ end
142
+
143
+ its(:state_name) { should == :executing }
144
+
145
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
146
+ lambda { subject.resumed! }.should raise_error(StateMachine::InvalidTransition)
147
+ end
148
+ end
149
+
150
+ describe '#stop_action' do
151
+ subject { command.stop_action }
152
+
153
+ its(:to_xml) { should == '<stop xmlns="urn:xmpp:rayo:1"/>' }
154
+ its(:component_id) { should == 'abc123' }
155
+ its(:call_id) { should == '123abc' }
156
+ end
157
+
158
+ describe '#stop!' do
159
+ describe "when the command is executing" do
160
+ before do
161
+ command.request!
162
+ command.execute!
163
+ end
164
+
165
+ it "should send its command properly" do
166
+ Connection.any_instance.expects(:write).with('123abc', command.stop_action, 'abc123')
167
+ command.stop!
168
+ end
169
+ end
170
+
171
+ describe "when the command is not executing" do
172
+ it "should raise an error" do
173
+ lambda { command.stop! }.should raise_error(InvalidActionError, "Cannot stop a Output that is not executing")
174
+ end
175
+ end
176
+ end # #stop!
177
+
178
+ describe "seeking" do
179
+ let(:seek_options) { {:direction => :forward, :amount => 1500} }
180
+
181
+ describe '#seek_action' do
182
+ subject { command.seek_action seek_options }
183
+
184
+ its(:to_xml) { should == '<seek xmlns="urn:xmpp:rayo:output:1" direction="forward" amount="1500"/>' }
185
+ its(:component_id) { should == 'abc123' }
186
+ its(:call_id) { should == '123abc' }
187
+ end
188
+
189
+ describe '#seek!' do
190
+ describe "when not seeking" do
191
+ before do
192
+ command.request!
193
+ command.execute!
194
+ end
195
+
196
+ it "should send its command properly" do
197
+ seek_action = command.seek_action seek_options
198
+ command.stubs(:seek_action).returns seek_action
199
+ Connection.any_instance.expects(:write).with('123abc', seek_action, 'abc123').returns true
200
+ command.expects :seeking!
201
+ command.expects :stopped_seeking!
202
+ command.seek! seek_options
203
+ seek_action.request!
204
+ seek_action.execute!
205
+ end
206
+ end
207
+
208
+ describe "when seeking" do
209
+ before { command.seeking! }
210
+
211
+ it "should raise an error" do
212
+ lambda { command.seek! }.should raise_error(InvalidActionError, "Cannot seek an Output that is already seeking.")
213
+ end
214
+ end
215
+ end
216
+
217
+ describe "#seeking!" do
218
+ before do
219
+ subject.request!
220
+ subject.execute!
221
+ subject.seeking!
222
+ end
223
+
224
+ its(:seek_status_name) { should == :seeking }
225
+
226
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
227
+ lambda { subject.seeking! }.should raise_error(StateMachine::InvalidTransition)
228
+ end
229
+ end
230
+
231
+ describe "#stopped_seeking!" do
232
+ before do
233
+ subject.request!
234
+ subject.execute!
235
+ subject.seeking!
236
+ subject.stopped_seeking!
237
+ end
238
+
239
+ its(:seek_status_name) { should == :not_seeking }
240
+
241
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
242
+ lambda { subject.stopped_seeking! }.should raise_error(StateMachine::InvalidTransition)
243
+ end
244
+ end
245
+ end
246
+
247
+ describe "adjusting speed" do
248
+ describe '#speed_up_action' do
249
+ subject { command.speed_up_action }
250
+
251
+ its(:to_xml) { should == '<speed-up xmlns="urn:xmpp:rayo:output:1"/>' }
252
+ its(:component_id) { should == 'abc123' }
253
+ its(:call_id) { should == '123abc' }
254
+ end
255
+
256
+ describe '#speed_up!' do
257
+ describe "when not altering speed" do
258
+ before do
259
+ command.request!
260
+ command.execute!
261
+ end
262
+
263
+ it "should send its command properly" do
264
+ speed_up_action = command.speed_up_action
265
+ command.stubs(:speed_up_action).returns speed_up_action
266
+ Connection.any_instance.expects(:write).with('123abc', speed_up_action, 'abc123').returns true
267
+ command.expects :speeding_up!
268
+ command.expects :stopped_speeding!
269
+ command.speed_up!
270
+ speed_up_action.request!
271
+ speed_up_action.execute!
272
+ end
273
+ end
274
+
275
+ describe "when speeding up" do
276
+ before { command.speeding_up! }
277
+
278
+ it "should raise an error" do
279
+ lambda { command.speed_up! }.should raise_error(InvalidActionError, "Cannot speed up an Output that is already speeding.")
280
+ end
281
+ end
282
+
283
+ describe "when slowing down" do
284
+ before { command.slowing_down! }
285
+
286
+ it "should raise an error" do
287
+ lambda { command.speed_up! }.should raise_error(InvalidActionError, "Cannot speed up an Output that is already speeding.")
288
+ end
289
+ end
290
+ end
291
+
292
+ describe "#speeding_up!" do
293
+ before do
294
+ subject.request!
295
+ subject.execute!
296
+ subject.speeding_up!
297
+ end
298
+
299
+ its(:speed_status_name) { should == :speeding_up }
300
+
301
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
302
+ lambda { subject.speeding_up! }.should raise_error(StateMachine::InvalidTransition)
303
+ end
304
+ end
305
+
306
+ describe '#slow_down_action' do
307
+ subject { command.slow_down_action }
308
+
309
+ its(:to_xml) { should == '<speed-down xmlns="urn:xmpp:rayo:output:1"/>' }
310
+ its(:component_id) { should == 'abc123' }
311
+ its(:call_id) { should == '123abc' }
312
+ end
313
+
314
+ describe '#slow_down!' do
315
+ describe "when not altering speed" do
316
+ before do
317
+ command.request!
318
+ command.execute!
319
+ end
320
+
321
+ it "should send its command properly" do
322
+ slow_down_action = command.slow_down_action
323
+ command.stubs(:slow_down_action).returns slow_down_action
324
+ Connection.any_instance.expects(:write).with('123abc', slow_down_action, 'abc123').returns true
325
+ command.expects :slowing_down!
326
+ command.expects :stopped_speeding!
327
+ command.slow_down!
328
+ slow_down_action.request!
329
+ slow_down_action.execute!
330
+ end
331
+ end
332
+
333
+ describe "when speeding up" do
334
+ before { command.speeding_up! }
335
+
336
+ it "should raise an error" do
337
+ lambda { command.slow_down! }.should raise_error(InvalidActionError, "Cannot slow down an Output that is already speeding.")
338
+ end
339
+ end
340
+
341
+ describe "when slowing down" do
342
+ before { command.slowing_down! }
343
+
344
+ it "should raise an error" do
345
+ lambda { command.slow_down! }.should raise_error(InvalidActionError, "Cannot slow down an Output that is already speeding.")
346
+ end
347
+ end
348
+ end
349
+
350
+ describe "#slowing_down!" do
351
+ before do
352
+ subject.request!
353
+ subject.execute!
354
+ subject.slowing_down!
355
+ end
356
+
357
+ its(:speed_status_name) { should == :slowing_down }
358
+
359
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
360
+ lambda { subject.slowing_down! }.should raise_error(StateMachine::InvalidTransition)
361
+ end
362
+ end
363
+
364
+ describe "#stopped_speeding!" do
365
+ before do
366
+ subject.request!
367
+ subject.execute!
368
+ subject.speeding_up!
369
+ subject.stopped_speeding!
370
+ end
371
+
372
+ its(:speed_status_name) { should == :not_speeding }
373
+
374
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
375
+ lambda { subject.stopped_speeding! }.should raise_error(StateMachine::InvalidTransition)
376
+ end
377
+ end
378
+ end
379
+
380
+ describe "adjusting volume" do
381
+ describe '#volume_up_action' do
382
+ subject { command.volume_up_action }
383
+
384
+ its(:to_xml) { should == '<volume-up xmlns="urn:xmpp:rayo:output:1"/>' }
385
+ its(:component_id) { should == 'abc123' }
386
+ its(:call_id) { should == '123abc' }
387
+ end
388
+
389
+ describe '#volume_up!' do
390
+ describe "when not altering volume" do
391
+ before do
392
+ command.request!
393
+ command.execute!
394
+ end
395
+
396
+ it "should send its command properly" do
397
+ volume_up_action = command.volume_up_action
398
+ command.stubs(:volume_up_action).returns volume_up_action
399
+ Connection.any_instance.expects(:write).with('123abc', volume_up_action, 'abc123').returns true
400
+ command.expects :voluming_up!
401
+ command.expects :stopped_voluming!
402
+ command.volume_up!
403
+ volume_up_action.request!
404
+ volume_up_action.execute!
405
+ end
406
+ end
407
+
408
+ describe "when voluming up" do
409
+ before { command.voluming_up! }
410
+
411
+ it "should raise an error" do
412
+ lambda { command.volume_up! }.should raise_error(InvalidActionError, "Cannot volume up an Output that is already voluming.")
413
+ end
414
+ end
415
+
416
+ describe "when voluming down" do
417
+ before { command.voluming_down! }
418
+
419
+ it "should raise an error" do
420
+ lambda { command.volume_up! }.should raise_error(InvalidActionError, "Cannot volume up an Output that is already voluming.")
421
+ end
422
+ end
423
+ end
424
+
425
+ describe "#voluming_up!" do
426
+ before do
427
+ subject.request!
428
+ subject.execute!
429
+ subject.voluming_up!
430
+ end
431
+
432
+ its(:volume_status_name) { should == :voluming_up }
433
+
434
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
435
+ lambda { subject.voluming_up! }.should raise_error(StateMachine::InvalidTransition)
436
+ end
437
+ end
438
+
439
+ describe '#volume_down_action' do
440
+ subject { command.volume_down_action }
441
+
442
+ its(:to_xml) { should == '<volume-down xmlns="urn:xmpp:rayo:output:1"/>' }
443
+ its(:component_id) { should == 'abc123' }
444
+ its(:call_id) { should == '123abc' }
445
+ end
446
+
447
+ describe '#volume_down!' do
448
+ describe "when not altering volume" do
449
+ before do
450
+ command.request!
451
+ command.execute!
452
+ end
453
+
454
+ it "should send its command properly" do
455
+ volume_down_action = command.volume_down_action
456
+ command.stubs(:volume_down_action).returns volume_down_action
457
+ Connection.any_instance.expects(:write).with('123abc', volume_down_action, 'abc123').returns true
458
+ command.expects :voluming_down!
459
+ command.expects :stopped_voluming!
460
+ command.volume_down!
461
+ volume_down_action.request!
462
+ volume_down_action.execute!
463
+ end
464
+ end
465
+
466
+ describe "when voluming up" do
467
+ before { command.voluming_up! }
468
+
469
+ it "should raise an error" do
470
+ lambda { command.volume_down! }.should raise_error(InvalidActionError, "Cannot volume down an Output that is already voluming.")
471
+ end
472
+ end
473
+
474
+ describe "when voluming down" do
475
+ before { command.voluming_down! }
476
+
477
+ it "should raise an error" do
478
+ lambda { command.volume_down! }.should raise_error(InvalidActionError, "Cannot volume down an Output that is already voluming.")
479
+ end
480
+ end
481
+ end
482
+
483
+ describe "#voluming_down!" do
484
+ before do
485
+ subject.request!
486
+ subject.execute!
487
+ subject.voluming_down!
488
+ end
489
+
490
+ its(:volume_status_name) { should == :voluming_down }
491
+
492
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
493
+ lambda { subject.voluming_down! }.should raise_error(StateMachine::InvalidTransition)
494
+ end
495
+ end
496
+
497
+ describe "#stopped_voluming!" do
498
+ before do
499
+ subject.request!
500
+ subject.execute!
501
+ subject.voluming_up!
502
+ subject.stopped_voluming!
503
+ end
504
+
505
+ its(:volume_status_name) { should == :not_voluming }
506
+
507
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
508
+ lambda { subject.stopped_voluming! }.should raise_error(StateMachine::InvalidTransition)
509
+ end
510
+ end
511
+ end
512
+ end
513
+ end
514
+
515
+ describe Output::Complete::Success do
516
+ let :stanza do
517
+ <<-MESSAGE
518
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
519
+ <success xmlns='urn:xmpp:rayo:output:complete:1' />
520
+ </complete>
521
+ MESSAGE
522
+ end
523
+
524
+ subject { RayoNode.import(parse_stanza(stanza).root).reason }
525
+
526
+ it { should be_instance_of Output::Complete::Success }
527
+
528
+ its(:name) { should == :success }
529
+ end
530
+ end
531
+ end # Punchblock