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,126 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
%w{
|
|
4
|
+
blather/client/dsl
|
|
5
|
+
punchblock/core_ext/blather/stanza
|
|
6
|
+
punchblock/core_ext/blather/stanza/presence
|
|
7
|
+
}.each { |f| require f }
|
|
8
|
+
|
|
9
|
+
module Punchblock
|
|
10
|
+
module Component
|
|
11
|
+
describe ComponentNode do
|
|
12
|
+
its(:event_queue) { should be_empty }
|
|
13
|
+
|
|
14
|
+
it "should not initially have a complete event set" do
|
|
15
|
+
subject.complete_event.set_yet?.should == false
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
describe "#add_event" do
|
|
19
|
+
let(:event) { Event::Complete.new }
|
|
20
|
+
|
|
21
|
+
before do
|
|
22
|
+
subject.request!
|
|
23
|
+
subject.execute!
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
let(:add_event) { subject.add_event event }
|
|
27
|
+
|
|
28
|
+
it "should add the event to the component's event queue" do
|
|
29
|
+
add_event
|
|
30
|
+
subject.event_queue.pop(false).should == event
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
it "should set the original event on the command" do
|
|
34
|
+
add_event
|
|
35
|
+
event.original_component.should == subject
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should trigger state transition" do
|
|
39
|
+
subject.expects(:transition_state!).once.with event
|
|
40
|
+
add_event
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
describe "with a complete event" do
|
|
44
|
+
it "should set the complete event resource" do
|
|
45
|
+
add_event
|
|
46
|
+
subject.complete_event.set_yet?.should == true
|
|
47
|
+
subject.complete_event.resource.should == event
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
describe "with another event" do
|
|
52
|
+
let(:event) { Event::Answered.new }
|
|
53
|
+
|
|
54
|
+
it "should not set the complete event resource" do
|
|
55
|
+
add_event
|
|
56
|
+
subject.complete_event.set_yet?.should == false
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe "with an event callback set" do
|
|
61
|
+
let(:event_callback) { lambda { |event| @foo = :bar } }
|
|
62
|
+
|
|
63
|
+
before do
|
|
64
|
+
@foo = nil
|
|
65
|
+
subject.event_callback = event_callback
|
|
66
|
+
add_event
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "should trigger the callback" do
|
|
70
|
+
@foo.should == :bar
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "should not write the event to the event queue" do
|
|
74
|
+
subject.event_queue.should be_empty
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe "which returns a falsy value" do
|
|
78
|
+
let(:event_callback) do
|
|
79
|
+
lambda { |event| false }
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
it "should add the event to the event queue" do
|
|
83
|
+
subject.event_queue.should_not be_empty
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
end # #add_event
|
|
88
|
+
|
|
89
|
+
describe "#transition_state!" do
|
|
90
|
+
describe "with a complete" do
|
|
91
|
+
it "should call #complete!" do
|
|
92
|
+
subject.expects(:complete!).once
|
|
93
|
+
subject.transition_state! Event::Complete.new
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
end # #transition_state!
|
|
97
|
+
|
|
98
|
+
describe "#response=" do
|
|
99
|
+
before do
|
|
100
|
+
subject.request!
|
|
101
|
+
subject.connection = mock(:record_command_id_for_iq_id => true)
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
let(:component_id) { 'abc123' }
|
|
105
|
+
|
|
106
|
+
let :ref do
|
|
107
|
+
Ref.new.tap do |ref|
|
|
108
|
+
ref.id = component_id
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
let :iq do
|
|
113
|
+
Blather::Stanza::Iq.new(:result, 'blah').tap do |iq|
|
|
114
|
+
iq.from = "12345@call.rayo.net"
|
|
115
|
+
iq << ref
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should set the component ID from the ref" do
|
|
120
|
+
subject.response = iq
|
|
121
|
+
subject.component_id.should == component_id
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
end # ComponentNode
|
|
125
|
+
end # Component
|
|
126
|
+
end # Punchblock
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
describe Connection do
|
|
5
|
+
let(:connection) { Connection.new :username => 1, :password => 1 }
|
|
6
|
+
|
|
7
|
+
subject { connection }
|
|
8
|
+
|
|
9
|
+
it 'should require a username and password to be passed in the options' do
|
|
10
|
+
expect { Connection.new :password => 1 }.to raise_error ArgumentError
|
|
11
|
+
expect { Connection.new :username => 1 }.to raise_error ArgumentError
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it 'should properly set the Blather logger' do
|
|
15
|
+
Connection.new :wire_logger => :foo, :username => 1, :password => 1
|
|
16
|
+
Blather.logger.should be :foo
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
its(:event_queue) { should be_a Queue }
|
|
20
|
+
|
|
21
|
+
it "looking up original command by command ID" do
|
|
22
|
+
offer = Event::Offer.new
|
|
23
|
+
offer.call_id = '9f00061'
|
|
24
|
+
offer.to = 'sip:whatever@127.0.0.1'
|
|
25
|
+
say = <<-MSG
|
|
26
|
+
<say xmlns='urn:xmpp:tropo:say:1' voice='allison'>
|
|
27
|
+
<audio url='http://acme.com/greeting.mp3'>
|
|
28
|
+
Thanks for calling ACME company
|
|
29
|
+
</audio>
|
|
30
|
+
<audio url='http://acme.com/package-shipped.mp3'>
|
|
31
|
+
Your package was shipped on
|
|
32
|
+
</audio>
|
|
33
|
+
<say-as interpret-as='date'>12/01/2011</say-as>
|
|
34
|
+
</say>
|
|
35
|
+
MSG
|
|
36
|
+
Component::Tropo::Say
|
|
37
|
+
say = RayoNode.import parse_stanza(say).root
|
|
38
|
+
connection.event_queue = []
|
|
39
|
+
connection.expects(:write_to_stream).once.returns true
|
|
40
|
+
iq = Blather::Stanza::Iq.new :set, '9f00061@call.rayo.net'
|
|
41
|
+
connection.expects(:create_iq).returns iq
|
|
42
|
+
|
|
43
|
+
write_thread = Thread.new do
|
|
44
|
+
connection.write offer.call_id, say
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
result = import_stanza <<-MSG
|
|
48
|
+
<iq type='result' from='16577@app.rayo.net/1' to='9f00061@call.rayo.net/1' id='#{iq.id}'>
|
|
49
|
+
<ref id='fgh4590' xmlns='urn:xmpp:rayo:1' />
|
|
50
|
+
</iq>
|
|
51
|
+
MSG
|
|
52
|
+
|
|
53
|
+
sleep 0.5 # Block so there's enough time for the write thread to get to the point where it's waiting on an IQ
|
|
54
|
+
|
|
55
|
+
connection.__send__ :handle_iq_result, result
|
|
56
|
+
|
|
57
|
+
write_thread.join
|
|
58
|
+
|
|
59
|
+
say.state_name.should == :executing
|
|
60
|
+
|
|
61
|
+
connection.original_component_from_id('fgh4590').should == say
|
|
62
|
+
|
|
63
|
+
example_complete = import_stanza <<-MSG
|
|
64
|
+
<presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
|
|
65
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
66
|
+
<success xmlns='urn:xmpp:tropo:say:complete:1' />
|
|
67
|
+
</complete>
|
|
68
|
+
</presence>
|
|
69
|
+
MSG
|
|
70
|
+
|
|
71
|
+
connection.__send__ :handle_presence, example_complete
|
|
72
|
+
say.event_queue.pop(false).source.should == say
|
|
73
|
+
|
|
74
|
+
say.component_id.should == 'fgh4590'
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
describe '#handle_presence' do
|
|
78
|
+
let :offer_xml do
|
|
79
|
+
<<-MSG
|
|
80
|
+
<presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net'>
|
|
81
|
+
<offer xmlns="urn:xmpp:rayo:1" to="sip:whatever@127.0.0.1" from="sip:ylcaomxb@192.168.1.9">
|
|
82
|
+
<header name="Max-Forwards" value="70"/>
|
|
83
|
+
<header name="Content-Length" value="367"/>
|
|
84
|
+
</offer>
|
|
85
|
+
</presence>
|
|
86
|
+
MSG
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
let(:example_offer) { import_stanza offer_xml }
|
|
90
|
+
|
|
91
|
+
it { example_offer.should be_a Blather::Stanza::Presence }
|
|
92
|
+
|
|
93
|
+
let :complete_xml do
|
|
94
|
+
<<-MSG
|
|
95
|
+
<presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
|
|
96
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
97
|
+
<success xmlns='urn:xmpp:tropo:say:complete:1' />
|
|
98
|
+
</complete>
|
|
99
|
+
</presence>
|
|
100
|
+
MSG
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
let(:example_complete) { import_stanza complete_xml }
|
|
104
|
+
|
|
105
|
+
it { example_complete.should be_a Blather::Stanza::Presence }
|
|
106
|
+
|
|
107
|
+
describe "event placed on the event queue" do
|
|
108
|
+
before do
|
|
109
|
+
connection.event_queue = []
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
describe "from an offer" do
|
|
113
|
+
before do
|
|
114
|
+
connection.__send__ :handle_presence, example_offer
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
subject { connection.event_queue.first }
|
|
118
|
+
|
|
119
|
+
it { should be_instance_of Event::Offer }
|
|
120
|
+
its(:call_id) { should == '9f00061' }
|
|
121
|
+
|
|
122
|
+
it "should populate the call map with the domain for the call ID" do
|
|
123
|
+
callmap = connection.instance_variable_get(:'@callmap')
|
|
124
|
+
callmap['9f00061'].should == 'call.rayo.net'
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
describe "from a complete" do
|
|
129
|
+
before do
|
|
130
|
+
connection.__send__ :handle_presence, example_complete
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
subject { connection.event_queue.first }
|
|
134
|
+
|
|
135
|
+
it { should be_instance_of Event::Complete }
|
|
136
|
+
its(:call_id) { should == '9f00061' }
|
|
137
|
+
its(:connection) { should == connection }
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
describe "from something that's not a real event" do
|
|
141
|
+
let :irrelevant_xml do
|
|
142
|
+
<<-MSG
|
|
143
|
+
<presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
|
|
144
|
+
<foo/>
|
|
145
|
+
</presence>
|
|
146
|
+
MSG
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
let(:example_irrelevant_event) { import_stanza irrelevant_xml }
|
|
150
|
+
|
|
151
|
+
before do
|
|
152
|
+
lambda { connection.__send__ :handle_presence, example_irrelevant_event }.should throw_symbol(:pass)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
subject { connection.event_queue }
|
|
156
|
+
|
|
157
|
+
it { should be_empty }
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
describe "#handle_error" do
|
|
163
|
+
let(:call_id) { "f6d437f4-1e18-457b-99f8-b5d853f50347" }
|
|
164
|
+
let(:component_id) { 'abc123' }
|
|
165
|
+
let :error_xml do
|
|
166
|
+
<<-MSG
|
|
167
|
+
<iq type="error" id="blather000e" from="f6d437f4-1e18-457b-99f8-b5d853f50347@10.0.1.11/abc123" to="usera@10.0.1.11/voxeo">
|
|
168
|
+
<output xmlns="urn:xmpp:rayo:output:1"/>
|
|
169
|
+
<error type="cancel">
|
|
170
|
+
<item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
|
|
171
|
+
<text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" lang="en">Could not find call [id=f6d437f4-1e18-457b-99f8-b5d853f50347]</text>
|
|
172
|
+
</error>
|
|
173
|
+
</iq>
|
|
174
|
+
MSG
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
let(:example_error) { import_stanza error_xml }
|
|
178
|
+
let(:cmd) { Component::Output.new }
|
|
179
|
+
|
|
180
|
+
before(:all) do
|
|
181
|
+
cmd.request!
|
|
182
|
+
connection.instance_variable_get(:'@iq_id_to_command')['blather000e'] = cmd
|
|
183
|
+
connection.__send__ :handle_error, example_error
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
subject { cmd.response }
|
|
187
|
+
|
|
188
|
+
its(:call_id) { should == call_id }
|
|
189
|
+
its(:component_id) { should == component_id }
|
|
190
|
+
its(:name) { should == :item_not_found }
|
|
191
|
+
its(:text) { should == 'Could not find call [id=f6d437f4-1e18-457b-99f8-b5d853f50347]' }
|
|
192
|
+
end
|
|
193
|
+
end # describe Connection
|
|
194
|
+
end # Punchblock
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe Answered do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:answered, 'urn:xmpp:rayo:1').should == Answered
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let(:stanza) { '<answered xmlns="urn:xmpp:rayo:1"/>' }
|
|
12
|
+
|
|
13
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
14
|
+
|
|
15
|
+
it { should be_instance_of Answered }
|
|
16
|
+
|
|
17
|
+
it_should_behave_like 'event'
|
|
18
|
+
|
|
19
|
+
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end # Punchblock
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe Complete do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:complete, 'urn:xmpp:rayo:ext:1').should == Complete
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let :stanza do
|
|
12
|
+
<<-MESSAGE
|
|
13
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
14
|
+
<success xmlns='urn:xmpp:tropo:say:complete:1' />
|
|
15
|
+
</complete>
|
|
16
|
+
MESSAGE
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
20
|
+
|
|
21
|
+
it { should be_instance_of Complete }
|
|
22
|
+
|
|
23
|
+
it_should_behave_like 'event'
|
|
24
|
+
|
|
25
|
+
its(:reason) { should be_instance_of Component::Tropo::Say::Complete::Success }
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe Complete::Stop do
|
|
30
|
+
let :stanza do
|
|
31
|
+
<<-MESSAGE
|
|
32
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
33
|
+
<stop xmlns='urn:xmpp:rayo:ext:complete:1' />
|
|
34
|
+
</complete>
|
|
35
|
+
MESSAGE
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
39
|
+
|
|
40
|
+
it { should be_instance_of Complete::Stop }
|
|
41
|
+
|
|
42
|
+
its(:name) { should == :stop }
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
describe Complete::Hangup do
|
|
46
|
+
let :stanza do
|
|
47
|
+
<<-MESSAGE
|
|
48
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
49
|
+
<hangup xmlns='urn:xmpp:rayo:ext:complete:1' />
|
|
50
|
+
</complete>
|
|
51
|
+
MESSAGE
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
55
|
+
|
|
56
|
+
it { should be_instance_of Complete::Hangup }
|
|
57
|
+
|
|
58
|
+
its(:name) { should == :hangup }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
describe Complete::Error do
|
|
62
|
+
let :stanza do
|
|
63
|
+
<<-MESSAGE
|
|
64
|
+
<complete xmlns='urn:xmpp:rayo:ext:1'>
|
|
65
|
+
<error xmlns='urn:xmpp:rayo:ext:complete:1'>
|
|
66
|
+
Something really bad happened
|
|
67
|
+
</error>
|
|
68
|
+
</complete>
|
|
69
|
+
MESSAGE
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
subject { RayoNode.import(parse_stanza(stanza).root).reason }
|
|
73
|
+
|
|
74
|
+
it { should be_instance_of Complete::Error }
|
|
75
|
+
|
|
76
|
+
its(:name) { should == :error }
|
|
77
|
+
its(:details) { should == "Something really bad happened" }
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end # Punchblock
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe DTMF do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:dtmf, 'urn:xmpp:rayo:1').should == DTMF
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let(:stanza) { "<dtmf xmlns='urn:xmpp:rayo:1' signal='#' />" }
|
|
12
|
+
|
|
13
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
14
|
+
|
|
15
|
+
it { should be_instance_of DTMF }
|
|
16
|
+
|
|
17
|
+
it_should_behave_like 'event'
|
|
18
|
+
|
|
19
|
+
its(:signal) { should == '#' }
|
|
20
|
+
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end # Punchblock
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe End do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:end, 'urn:xmpp:rayo:1').should == End
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let :stanza do
|
|
12
|
+
<<-MESSAGE
|
|
13
|
+
<end xmlns="urn:xmpp:rayo:1">
|
|
14
|
+
<timeout />
|
|
15
|
+
</end>
|
|
16
|
+
MESSAGE
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
20
|
+
|
|
21
|
+
it { should be_instance_of End }
|
|
22
|
+
|
|
23
|
+
it_should_behave_like 'event'
|
|
24
|
+
|
|
25
|
+
its(:reason) { should == :timeout }
|
|
26
|
+
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end # Punchblock
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe Info do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:info, 'urn:xmpp:rayo:1').should == Info
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let :stanza do
|
|
12
|
+
<<-MESSAGE
|
|
13
|
+
<info xmlns='urn:xmpp:rayo:1'>
|
|
14
|
+
<something/>
|
|
15
|
+
</info>
|
|
16
|
+
MESSAGE
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
20
|
+
|
|
21
|
+
it { should be_instance_of Info }
|
|
22
|
+
|
|
23
|
+
it_should_behave_like 'event'
|
|
24
|
+
|
|
25
|
+
its(:event_name) { should == :something }
|
|
26
|
+
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end # Punchblock
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe Joined do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:joined, 'urn:xmpp:rayo:1').should == Joined
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let(:stanza) { '<joined xmlns="urn:xmpp:rayo:1" call-id="b" mixer-id="m" />' }
|
|
12
|
+
|
|
13
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
14
|
+
|
|
15
|
+
it { should be_instance_of Joined }
|
|
16
|
+
|
|
17
|
+
it_should_behave_like 'event'
|
|
18
|
+
|
|
19
|
+
its(:other_call_id) { should == 'b' }
|
|
20
|
+
its(:mixer_id) { should == 'm' }
|
|
21
|
+
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "when setting options in initializer" do
|
|
25
|
+
subject { Joined.new :other_call_id => 'abc123', :mixer_id => 'blah' }
|
|
26
|
+
|
|
27
|
+
its(:other_call_id) { should == 'abc123' }
|
|
28
|
+
its(:mixer_id) { should == 'blah' }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end # Punchblock
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe Offer do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:offer, 'urn:xmpp:rayo:1').should == Offer
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let :stanza do
|
|
12
|
+
<<-MESSAGE
|
|
13
|
+
<offer xmlns='urn:xmpp:rayo:1'
|
|
14
|
+
to='tel:+18003211212'
|
|
15
|
+
from='tel:+13058881212'>
|
|
16
|
+
<!-- Signaling (e.g. SIP) Headers -->
|
|
17
|
+
<header name="x-skill" value="agent" />
|
|
18
|
+
<header name="x-customer-id" value="8877" />
|
|
19
|
+
</offer>
|
|
20
|
+
MESSAGE
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
24
|
+
|
|
25
|
+
it { should be_instance_of Offer }
|
|
26
|
+
|
|
27
|
+
it_should_behave_like 'event'
|
|
28
|
+
it_should_behave_like 'event_headers'
|
|
29
|
+
|
|
30
|
+
its(:to) { should == 'tel:+18003211212' }
|
|
31
|
+
its(:from) { should == 'tel:+13058881212' }
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end # Punchblock
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe Ringing do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:ringing, 'urn:xmpp:rayo:1').should == Ringing
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let(:stanza) { '<ringing xmlns="urn:xmpp:rayo:1"/>' }
|
|
12
|
+
|
|
13
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
14
|
+
|
|
15
|
+
it { should be_instance_of Ringing }
|
|
16
|
+
|
|
17
|
+
it_should_behave_like 'event'
|
|
18
|
+
|
|
19
|
+
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end # Punchblock
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
class Event
|
|
5
|
+
describe Unjoined do
|
|
6
|
+
it 'registers itself' do
|
|
7
|
+
RayoNode.class_from_registration(:unjoined, 'urn:xmpp:rayo:1').should == Unjoined
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
describe "from a stanza" do
|
|
11
|
+
let(:stanza) { '<unjoined xmlns="urn:xmpp:rayo:1" call-id="b" mixer-id="m" />' }
|
|
12
|
+
|
|
13
|
+
subject { RayoNode.import parse_stanza(stanza).root, '9f00061', '1' }
|
|
14
|
+
|
|
15
|
+
it { should be_instance_of Unjoined }
|
|
16
|
+
|
|
17
|
+
it_should_behave_like 'event'
|
|
18
|
+
|
|
19
|
+
its(:other_call_id) { should == 'b' }
|
|
20
|
+
its(:mixer_id) { should == 'm' }
|
|
21
|
+
its(:xmlns) { should == 'urn:xmpp:rayo:1' }
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
describe "when setting options in initializer" do
|
|
25
|
+
subject { Unjoined.new :other_call_id => 'abc123', :mixer_id => 'blah' }
|
|
26
|
+
|
|
27
|
+
its(:other_call_id) { should == 'abc123' }
|
|
28
|
+
its(:mixer_id) { should == 'blah' }
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end # Punchblock
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
describe Header do
|
|
5
|
+
it 'will auto-inherit nodes' do
|
|
6
|
+
n = parse_stanza "<header name='boo' value='bah' />"
|
|
7
|
+
h = Header.new n.root
|
|
8
|
+
h.name.should == :boo
|
|
9
|
+
h.value.should == 'bah'
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it 'has a name attribute' do
|
|
13
|
+
n = Header.new :boo, 'bah'
|
|
14
|
+
n.name.should == :boo
|
|
15
|
+
n.name = :foo
|
|
16
|
+
n.name.should == :foo
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "substitutes - for _ on the name attribute when reading" do
|
|
20
|
+
n = parse_stanza "<header name='boo-bah' value='foo' />"
|
|
21
|
+
h = Header.new n.root
|
|
22
|
+
h.name.should == :boo_bah
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
it "substitutes _ for - on the name attribute when writing" do
|
|
26
|
+
h = Header.new :boo_bah, 'foo'
|
|
27
|
+
h.to_xml.should == '<header name="boo-bah" value="foo"/>'
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
it 'has a value attribute' do
|
|
31
|
+
n = Header.new :boo, 'en'
|
|
32
|
+
n.value.should == 'en'
|
|
33
|
+
n.value = 'de'
|
|
34
|
+
n.value.should == 'de'
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it 'can determine equality' do
|
|
38
|
+
a = Header.new :boo, 'bah'
|
|
39
|
+
a.should == Header.new(:boo, 'bah')
|
|
40
|
+
a.should_not == Header.new(:bah, 'bah')
|
|
41
|
+
a.should_not == Header.new(:boo, 'boo')
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end # Punchblock
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
module Punchblock
|
|
4
|
+
describe ProtocolError do
|
|
5
|
+
subject { ProtocolError.new :item_not_found, 'Could not find call [id=f6d437f4-1e18-457b-99f8-b5d853f50347]', 'f6d437f4-1e18-457b-99f8-b5d853f50347', 'abc123' }
|
|
6
|
+
|
|
7
|
+
its(:inspect) { should == '#<Punchblock::ProtocolError: name=:item_not_found text="Could not find call [id=f6d437f4-1e18-457b-99f8-b5d853f50347]" call_id="f6d437f4-1e18-457b-99f8-b5d853f50347" component_id="abc123">' }
|
|
8
|
+
end
|
|
9
|
+
end
|