tropo-webapi-sdk-ruby 15.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/LICENSE +21 -0
- data/README.md +249 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/examples/sinatra_server.rb +194 -0
- data/lib/tropo-webapi-ruby/object_patch.rb +13 -0
- data/lib/tropo-webapi-ruby/tropo-webapi-ruby-helpers.rb +253 -0
- data/lib/tropo-webapi-ruby/tropo-webapi-ruby.rb +903 -0
- data/lib/tropo-webapi-ruby.rb +5 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/tropo-webapi-ruby_spec.rb +637 -0
- data/tropo-webapi-ruby.gemspec +58 -0
- metadata +99 -0
@@ -0,0 +1,637 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe "Tropo" do
|
4
|
+
|
5
|
+
|
6
|
+
response = Tropo::Generator.wait({ :milliseconds => 10, :allowSignals => "exit"})
|
7
|
+
|
8
|
+
# Ask action tests (and alias Prompt)
|
9
|
+
it "should generate a complete 'ask' JSON document" do
|
10
|
+
response = Tropo::Generator.ask({ :name => 'foo',
|
11
|
+
:bargein => 'true',
|
12
|
+
:timeout => 30,
|
13
|
+
:require => 'true' })
|
14
|
+
JSON.parse(response).should == { "tropo" => [{ "ask" => { "name" => "foo", "bargein" => "true", "timeout" => 30, "require" => "true" } }] }
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should generate an 'ask' JSON document when a block is passed" do
|
18
|
+
response = Tropo::Generator.ask({ :name => 'foo',
|
19
|
+
:bargein => 'true',
|
20
|
+
:timeout => 30,
|
21
|
+
:require => 'true' }) do
|
22
|
+
say :value => 'Please say your account number'
|
23
|
+
choices :value => '[5 DIGITS]'
|
24
|
+
end
|
25
|
+
JSON.parse(response).should == {"tropo"=>[{"ask"=>{"name"=>"foo", "say"=>[{"value"=>"Please say your account number"}], "bargein"=>"true", "timeout"=>30, "require"=>"true", "choices"=>{"value"=>"[5 DIGITS]"}}}]}
|
26
|
+
end
|
27
|
+
|
28
|
+
# There is currently a feature request to support an on within an ask
|
29
|
+
#
|
30
|
+
# it "should generate an 'ask' JSON document when a block is passed with an 'on' action" do
|
31
|
+
# response = Tropo::Generator.ask({ :name => 'foo',
|
32
|
+
# :bargein => 'true',
|
33
|
+
# :timeout => 30,
|
34
|
+
# :require => 'true' }) do
|
35
|
+
# say :value => 'Please say your account number'
|
36
|
+
# choices :value => '[5 DIGITS]'
|
37
|
+
# on :event => 'success', :next => '/result.json'
|
38
|
+
# end
|
39
|
+
# JSON.parse(response).should == {"tropo"=>[{"ask"=>{"name"=>"foo", "say"=>[{"value"=>"Please say your account number"}], "bargein"=>"true", "timeout"=>30, "require"=>"true", "on"=>[{"event"=>"success", "next"=>"/result.json"}], "choices"=>{"value"=>"[5 DIGITS]"}}}]}
|
40
|
+
# end
|
41
|
+
|
42
|
+
it "should generate an error if an 'ask' is passed without a 'name' parameter" do
|
43
|
+
begin
|
44
|
+
response = Tropo::Generator.ask({ :foo => 'bar' })
|
45
|
+
rescue => err
|
46
|
+
err.to_s.should == "A 'name' must be provided to a 'ask' action"
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# Prompt
|
51
|
+
it "should generate a complete 'prompt' JSON document" do
|
52
|
+
response = Tropo::Generator.prompt({ :name => 'foo',
|
53
|
+
:bargein => 'true',
|
54
|
+
:timeout => 30,
|
55
|
+
:require => 'true' })
|
56
|
+
JSON.parse(response).should == { "tropo" => [{ "ask" => { "name" => "foo", "bargein" => "true", "timeout" => 30, "require" => "true" } }] }
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should generate an 'prompt' JSON document when a block is passed" do
|
60
|
+
response = Tropo::Generator.prompt({ :name => 'foo',
|
61
|
+
:bargein => 'true',
|
62
|
+
:timeout => 30,
|
63
|
+
:require => 'true' }) do
|
64
|
+
say :value => 'Please say your account number'
|
65
|
+
choices :value => '[5 DIGITS]'
|
66
|
+
end
|
67
|
+
JSON.parse(response).should == {"tropo"=>[{"ask"=>{"name"=>"foo", "say"=>[{"value"=>"Please say your account number"}], "bargein"=>"true", "timeout"=>30, "require"=>"true", "choices"=>{"value"=>"[5 DIGITS]"}}}]}
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should generate an error if an 'prompt' is passed without a 'name' parameter" do
|
71
|
+
begin
|
72
|
+
response = Tropo::Generator.prompt({ :foo => 'bar' })
|
73
|
+
rescue => err
|
74
|
+
err.to_s.should == "A 'name' must be provided to a 'ask' action"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Choices tests
|
79
|
+
it "should generate a standard 'choices' JSON document" do
|
80
|
+
response = Tropo::Generator.choices({ :value => '[5 DIGITS]' })
|
81
|
+
JSON.parse(response).should == { 'tropo' => [{ 'choices' => { 'value' => '[5 DIGITS]' } }] }
|
82
|
+
end
|
83
|
+
|
84
|
+
it "should raise an error if a 'choices' passes an unspported mode" do
|
85
|
+
begin
|
86
|
+
response = Tropo::Generator.choices({ :value => '[5 DIGITS]', :mode => 'frootloops' })
|
87
|
+
rescue => err
|
88
|
+
err.to_s.should == "If mode is provided, only 'dtmf', 'speech' or 'any' is supported"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should generate a standard 'choices' JSON document with a mode" do
|
93
|
+
response = Tropo::Generator.choices({ :value => '[5 DIGITS]', :mode => 'dtmf' })
|
94
|
+
JSON.parse(response).should == { 'tropo' => [{ 'choices' => { 'value' => '[5 DIGITS]', 'mode' => 'dtmf' } }] }
|
95
|
+
end
|
96
|
+
|
97
|
+
# Conference action tests
|
98
|
+
it "should generate a complete 'conference' JSON document" do
|
99
|
+
response = Tropo::Generator.conference({ :name => 'foo',
|
100
|
+
:id => '1234',
|
101
|
+
:mute => false,
|
102
|
+
:send_tones => false,
|
103
|
+
:exit_tone => '#' })
|
104
|
+
JSON.parse(response).should == {"tropo"=>[{"conference"=>{"name"=>"foo", "mute"=>false, "sendTones"=>false, "id"=>"1234", "exitTone"=>"#"}}]}
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should generate a complete 'conference' JSON document when a block is passed" do
|
108
|
+
response = Tropo::Generator.conference({ :name => 'foo',
|
109
|
+
:id => '1234',
|
110
|
+
:mute => false,
|
111
|
+
:send_tones => false,
|
112
|
+
:exit_tone => '#' }) do
|
113
|
+
on(:event => 'join') { say :value => 'Welcome to the conference' }
|
114
|
+
on(:event => 'leave') { say :value => 'Someone has left the conference' }
|
115
|
+
end
|
116
|
+
JSON.parse(response).should == {"tropo"=>[{"conference"=>{"name"=>"foo", "mute"=>false, "id"=>"1234", "exitTone"=>"#", "sendTones"=>false, "on"=>[{"say"=>[{"value"=>"Welcome to the conference"}], "event"=>"join"}, {"say"=>[{"value"=>"Someone has left the conference"}], "event"=>"leave"}]}}]}
|
117
|
+
end
|
118
|
+
|
119
|
+
it "should generate an error if an 'conference' is passed without a 'name' parameter" do
|
120
|
+
begin
|
121
|
+
response = Tropo::Generator.conference({ :foo => 'bar' })
|
122
|
+
rescue => err
|
123
|
+
err.to_s.should == "A 'name' must be provided to a 'conference' action"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should generate an error if an 'conference' is passed without an 'id' parameter" do
|
128
|
+
begin
|
129
|
+
response = Tropo::Generator.conference({ :name => 'bar' })
|
130
|
+
rescue => err
|
131
|
+
err.to_s.should == "A 'id' must be provided to a 'conference' action"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
# Hangup action tests and Disconnect alias
|
136
|
+
it "should generate a JSON document with a 'hangup' action" do
|
137
|
+
response = Tropo::Generator.hangup
|
138
|
+
JSON.parse(response).should == {"tropo"=>[{"hangup"=>nil}]}
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should generate a JSON document with a 'disconnect' action" do
|
142
|
+
response = Tropo::Generator.disconnect
|
143
|
+
JSON.parse(response).should == {"tropo"=>[{"hangup"=>nil}]}
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should generate a standard 'on' JSON document" do
|
147
|
+
response = Tropo::Generator.on({ :event => 'hangup', :next => 'myresource' })
|
148
|
+
JSON.parse(response).should == { "tropo" => [{ "on" =>{ "event" => "hangup", "next" => "myresource" } }] }
|
149
|
+
end
|
150
|
+
|
151
|
+
# On tests
|
152
|
+
it "should generate a an error of an 'on' document does not pass an event param" do
|
153
|
+
begin
|
154
|
+
response = Tropo::Generator.on({ :foo => 'bar' })
|
155
|
+
rescue => err
|
156
|
+
err.to_s.should == "A 'event' must be provided to a 'on' action"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
it "should generate a an error of an 'on' document does not pass an event param" do
|
161
|
+
begin
|
162
|
+
response = Tropo::Generator.on({ :event => 'bar' })
|
163
|
+
rescue => err
|
164
|
+
err.to_s.should == "A 'next' resource must be provided"
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
# Record action tests
|
169
|
+
it "should generate a complete 'record' JSON document" do
|
170
|
+
response = Tropo::Generator.record({ :name => 'foo',
|
171
|
+
:url => 'http://sendme.com/tropo',
|
172
|
+
:beep => true,
|
173
|
+
:send_tones => false,
|
174
|
+
:exit_tone => '#' })
|
175
|
+
JSON.parse(response).should == {"tropo"=>[{"record"=>{"name"=>"foo", "beep"=>true, "url"=>"http://sendme.com/tropo", "exitTone"=>"#", "sendTones"=>false}}]}
|
176
|
+
end
|
177
|
+
|
178
|
+
it "should generate a complete 'record' JSON document when a block is passed" do
|
179
|
+
response = Tropo::Generator.record({ :name => 'foo',
|
180
|
+
:url => 'http://sendme.com/tropo',
|
181
|
+
:beep => true,
|
182
|
+
:send_tones => false,
|
183
|
+
:exit_tone => '#' }) do
|
184
|
+
say :value => 'Please say your account number'
|
185
|
+
choices :value => '[5 DIGITS]'
|
186
|
+
end
|
187
|
+
JSON.parse(response).should == {"tropo"=>[{"record"=>{"name"=>"foo", "say"=>[{"value"=>"Please say your account number"}], "beep"=>true, "url"=>"http://sendme.com/tropo", "sendTones"=>false, "exitTone"=>"#", "choices"=>{"value"=>"[5 DIGITS]"}}}]}
|
188
|
+
end
|
189
|
+
|
190
|
+
it "should generate an error if an 'record' is passed without a 'name' parameter" do
|
191
|
+
begin
|
192
|
+
response = Tropo::Generator.record({ :foo => 'bar' })
|
193
|
+
rescue => err
|
194
|
+
err.to_s.should == "A 'name' must be provided to a 'record' action"
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
it "should generate an error if an 'record' is passed without an 'url' parameter" do
|
199
|
+
begin
|
200
|
+
response = Tropo::Generator.record({ :name => 'bar' })
|
201
|
+
rescue => err
|
202
|
+
err.to_s.should == "A 'url' must be provided to a 'record' action"
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
it "should generate an error if an 'record' is passed without an invalid 'url' parameter" do
|
207
|
+
begin
|
208
|
+
response = Tropo::Generator.record({ :name => 'bar',
|
209
|
+
:url => 'foobar' })
|
210
|
+
rescue => err
|
211
|
+
err.to_s.should == "The 'url' paramater must be a valid URL"
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
it "should accept a valid email address when a 'record' action is called" do
|
216
|
+
response = Tropo::Generator.record({ :name => 'bar',
|
217
|
+
:url => 'foo@bar.com' })
|
218
|
+
JSON.parse(response).should == JSON.parse("{\"tropo\":[{\"record\":{\"url\":\"foo@bar.com\",\"name\":\"bar\"}}]}")
|
219
|
+
end
|
220
|
+
|
221
|
+
# Redirect action tests
|
222
|
+
it "should generate a JSON document with a 'redirect' action" do
|
223
|
+
response = Tropo::Generator.redirect({ :to => 'sip:1234', :from => '4155551212' })
|
224
|
+
JSON.parse(response).should == {"tropo"=>[{"redirect"=>{"from"=>"4155551212", "to"=>"sip:1234"}}]}
|
225
|
+
end
|
226
|
+
|
227
|
+
it "should generate an error if a 'redirect' action is included in a block" do
|
228
|
+
begin
|
229
|
+
response = Tropo::Generator.conference(:name => 'foobar', :id => 1234) do
|
230
|
+
redirect(:to => 'sip:1234', :from => '4155551212')
|
231
|
+
end
|
232
|
+
rescue => err
|
233
|
+
err.to_s.should == 'Redirect should only be used alone and before the session is answered, use transfer instead'
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
it "should generate an error when no 'to' is passed to a 'redirect' action" do
|
238
|
+
begin
|
239
|
+
response = Tropo::Generator.redirect
|
240
|
+
rescue => err
|
241
|
+
err.to_s.should == "A 'to' must be provided to a 'redirect' action"
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
# Reject action tests
|
246
|
+
it "should generate a JSON document with a 'reject' action" do
|
247
|
+
response = Tropo::Generator.reject
|
248
|
+
JSON.parse(response).should == {"tropo"=>[{"reject"=>nil}]}
|
249
|
+
end
|
250
|
+
|
251
|
+
# Say action tests
|
252
|
+
it "should generate a standard 'say' JSON document when a stiring is passed" do
|
253
|
+
JSON.parse(Tropo::Generator.say('1234')).should == { "tropo" => [{ "say" => [{ "value" => "1234" }] }] }
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should generate an error if I try to pass an integer to a 'say' action" do
|
257
|
+
begin
|
258
|
+
Tropo::Generator.say(1234)
|
259
|
+
rescue => err
|
260
|
+
err.to_s.should == "An invalid paramater type Fixnum has been passed"
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should generate a standard 'say' JSON document" do
|
265
|
+
JSON.parse(Tropo::Generator.say({ :value => '1234' })).should == { "tropo" => [{ "say" => [{ "value" => "1234" }] }] }
|
266
|
+
end
|
267
|
+
|
268
|
+
it "should generate a 'say' JSON document when an array of values is passed" do
|
269
|
+
response = Tropo::Generator.say([{ :value => '1234' }, { :value => 'abcd', :event => 'nomatch:1' }])
|
270
|
+
JSON.parse(response).should == { "tropo" => [{ "say" => [{ "value" => "1234" }, { "value" => "abcd", "event"=>"nomatch:1" }] }] }
|
271
|
+
end
|
272
|
+
|
273
|
+
it "should generate an error if no 'value' key is passed to a 'say' request" do
|
274
|
+
begin
|
275
|
+
response = Tropo::Generator.say({ :name => 'foo' })
|
276
|
+
rescue => err
|
277
|
+
err.to_s.should == "A 'value' must be provided to a 'say' action"
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
it "should generate a JSON document with a 'say' and an 'on'" do
|
282
|
+
result = Tropo::Generator.new do
|
283
|
+
say :value => 'blah'
|
284
|
+
on :event => 'error', :next => 'error.json'
|
285
|
+
end
|
286
|
+
JSON.parse(result.response).should == {"tropo"=>[{"say"=>[{"value"=>"blah"}]}, {"on"=>{"event"=>"error", "next"=>"error.json"}}]}
|
287
|
+
end
|
288
|
+
|
289
|
+
# Start & Stop Recording actions tests
|
290
|
+
it "should generate a JSON document with a 'start_recording' action" do
|
291
|
+
response = Tropo::Generator.start_recording(:url => 'http://postrecording.com/tropo')
|
292
|
+
JSON.parse(response).should == {"tropo"=>[{"startRecording"=>{"url"=>"http://postrecording.com/tropo"}}]}
|
293
|
+
end
|
294
|
+
|
295
|
+
it "should generate a JSON document with a 'start_call_recording' action" do
|
296
|
+
response = Tropo::Generator.start_call_recording(:url => 'http://postrecording.com/tropo')
|
297
|
+
JSON.parse(response).should == {"tropo"=>[{"startRecording"=>{"url"=>"http://postrecording.com/tropo"}}]}
|
298
|
+
end
|
299
|
+
|
300
|
+
it "should generate a JSON document with a 'stopRecording' action" do
|
301
|
+
response = Tropo::Generator.stop_call_recording
|
302
|
+
JSON.parse(response).should == {"tropo"=>[{"stopRecording"=>nil}]}
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should generate a JSON document with a 'stoprecording' action" do
|
306
|
+
response = Tropo::Generator.stop_recording
|
307
|
+
JSON.parse(response).should == {"tropo"=>[{"stopRecording"=>nil}]}
|
308
|
+
end
|
309
|
+
|
310
|
+
# Transfer action tests
|
311
|
+
it "should generate a JSON document with a 'transfer' action" do
|
312
|
+
response = Tropo::Generator.transfer(:to => 'tel:+14157044517')
|
313
|
+
JSON.parse(response).should == {"tropo"=>[{"transfer"=>{"to"=>"tel:+14157044517"}}]}
|
314
|
+
end
|
315
|
+
|
316
|
+
# Transfer action tests
|
317
|
+
it "should generate a JSON document with a 'transfer' action with an 'on' and 'choices' actions" do
|
318
|
+
response = Tropo::Generator.transfer(:to => 'tel:+14157044517') do
|
319
|
+
on :event => 'unbounded', :next => '/error.json'
|
320
|
+
choices :value => '[5 DIGITS]'
|
321
|
+
end
|
322
|
+
JSON.parse(response).should == {"tropo"=>[{"transfer"=>{"to"=>"tel:+14157044517", "choices"=>{"value"=>"[5 DIGITS]"}, "on"=>[{"event"=>"unbounded", "next"=>"/error.json"}]}}]}
|
323
|
+
end
|
324
|
+
|
325
|
+
it "should generate an error if no 'to' key is passed to a 'transfer' request" do
|
326
|
+
begin
|
327
|
+
response = Tropo::Generator.transfer
|
328
|
+
rescue => err
|
329
|
+
err.to_s.should == "A 'to' must be provided to a 'transfer' action"
|
330
|
+
end
|
331
|
+
end
|
332
|
+
|
333
|
+
# General tests
|
334
|
+
it "should generate a JSON document when a block is passed" do
|
335
|
+
result = Tropo::Generator.new do
|
336
|
+
say [{ :value => '1234' }, { :value => 'abcd', :event => "nomatch:1" }]
|
337
|
+
say [{ :value => '0987' }, { :value => 'zyxw', :event => "nomatch:2" }]
|
338
|
+
end
|
339
|
+
JSON.parse(result.response).should == {"tropo"=>[{"say"=>[{"value"=>"1234"}, {"value"=>"abcd", "event"=>"nomatch:1"}]}, {"say"=>[{"value"=>"0987"}, {"value"=>"zyxw", "event"=>"nomatch:2"}]}]}
|
340
|
+
end
|
341
|
+
|
342
|
+
it "should build a Ruby hash object when a session arrives in JSON" do
|
343
|
+
json_session = "{\"session\":{\"id\":\"dih06n\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:48.562Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"tropomessaging@bot.im\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"},\"from\":{\"id\":\"john_doe@gmail.com\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"}}}"
|
344
|
+
hash = Tropo::Generator.parse(json_session)
|
345
|
+
hash[:session][:timestamp] == Time.parse('2010-01-19T18:27:46.852-05:00')
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should build a Ruby hash object when a result arrives in JSON" do
|
349
|
+
json_result = "{\"result\":{\"sessionId\":\"sessionId\",\"callState\":\"ANSWERED\",\"sessionDuration\":10,\"sequence\":1,\"complete\":true,\"error\":\"error\",\"properties\":[{\"key\":\"foo\",\"value\":\"bar\"},{\"key\":\"charlie\",\"value\":\"foxtrot\"}],\"actions\":{\"name\":\"pin\",\"attempts\":1,\"disposition\":\"SUCCESS\",\"confidence\":100,\"interpretation\":\"12345\",\"utterance\":\"1 2 3 4 5\"}}}"
|
350
|
+
Tropo::Generator.parse(json_result).should == Hashie::Mash.new({:result=>{:session_id=>"sessionId", :properties=>{:foo=>{:value=>"bar"}, :charlie=>{:value=>"foxtrot"}}, :complete=>true, :call_state=>"ANSWERED", :actions=>{:pin=>{:disposition=>"SUCCESS", :utterance=>"1 2 3 4 5", :attempts=>1, :interpretation=>"12345", :confidence=>100}}, :session_duration=>10, :error=>"error", :sequence=>1}})
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should build a ruby hash object when a realworld JSON string arrives" do
|
354
|
+
json_result = "{\"result\":{\"sessionId\":\"CCFD9C86-1DD1-11B2-B76D-B9B253E4B7FB@161.253.55.20\",\"callState\":\"ANSWERED\",\"sessionDuration\":2,\"sequence\":1,\"complete\":true,\"error\":null,\"actions\":[{\"name\":\"zip\",\"attempts\":1,\"disposition\":\"SUCCESS\",\"confidence\":100,\"interpretation\":\"12345\",\"utterance\":\"1 2 3 4 5\"},{\"name\":\"days\",\"attempts\":1,\"disposition\":\"SUCCESS\",\"confidence\":100,\"interpretation\":\"1\",\"utterance\":\"1\"}]}}"
|
355
|
+
Tropo::Generator.parse(json_result).should == Hashie::Mash.new({:result=>{:call_state=>"ANSWERED", :complete=>true, :actions=>{:zip=>{:disposition=>"SUCCESS", :utterance=>"1 2 3 4 5", :attempts=>1, :interpretation=>"12345", :confidence=>100}, :days=>{:disposition=>"SUCCESS", :utterance=>"1", :attempts=>1, :interpretation=>"1", :confidence=>100}}, :session_duration=>2, :sequence=>1, :session_id=>"CCFD9C86-1DD1-11B2-B76D-B9B253E4B7FB@161.253.55.20", :error=>nil}})
|
356
|
+
end
|
357
|
+
|
358
|
+
it "should see an object delcared outside of a block" do
|
359
|
+
@@session = 'foobar'
|
360
|
+
result = Tropo::Generator.new do
|
361
|
+
@@new_session = @@session
|
362
|
+
say :value => 'blah'
|
363
|
+
on :event => 'error', :next => 'error.json'
|
364
|
+
end
|
365
|
+
@@new_session.should == 'foobar'
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should allow you to create a Tropo::Generator object and build up a JSON request with two says" do
|
369
|
+
tropo = Tropo::Generator.new
|
370
|
+
tropo.say('foo')
|
371
|
+
tropo.say('bar')
|
372
|
+
tropo.response.should == "{\"tropo\":[{\"say\":[{\"value\":\"foo\"}]},{\"say\":[{\"value\":\"bar\"}]}]}"
|
373
|
+
end
|
374
|
+
|
375
|
+
it "should allow you to create a Tropo::Generator object and build up a JSON request with: a say, an on and a record" do
|
376
|
+
tropo = Tropo::Generator.new
|
377
|
+
tropo.say 'Welcome to the app'
|
378
|
+
tropo.on :event => 'hangup', :next => '/hangup.json'
|
379
|
+
tropo.record({ :name => 'foo',
|
380
|
+
:url => 'http://sendme.com/tropo',
|
381
|
+
:beep => true,
|
382
|
+
:send_tones => false,
|
383
|
+
:exit_tone => '#' }) do
|
384
|
+
say :value => 'Please say your account number'
|
385
|
+
choices :value => '[5 DIGITS]'
|
386
|
+
end
|
387
|
+
JSON.parse(tropo.response).should == {"tropo"=>[{"say"=>[{"value"=>"Welcome to the app"}]}, {"on"=>{"event"=>"hangup", "next"=>"/hangup.json"}}, {"record"=>{"name"=>"foo", "say"=>[{"value"=>"Please say your account number"}], "beep"=>true, "url"=>"http://sendme.com/tropo", "sendTones"=>false, "exitTone"=>"#", "choices"=>{"value"=>"[5 DIGITS]"}}}]}
|
388
|
+
end
|
389
|
+
|
390
|
+
it "should allow you to reset the object to a fresh response after building a response first" do
|
391
|
+
tropo = Tropo::Generator.new
|
392
|
+
tropo.say 'Welcome to the app'
|
393
|
+
tropo.on :event => 'hangup', :next => '/hangup.json'
|
394
|
+
tropo.record({ :name => 'foo',
|
395
|
+
:url => 'http://sendme.com/tropo',
|
396
|
+
:beep => true,
|
397
|
+
:send_tones => false,
|
398
|
+
:exit_tone => '#' }) do
|
399
|
+
say :value => 'Please say your account number'
|
400
|
+
choices :value => '[5 DIGITS]'
|
401
|
+
end
|
402
|
+
JSON.parse(tropo.response).should == {"tropo"=>[{"say"=>[{"value"=>"Welcome to the app"}]}, {"on"=>{"event"=>"hangup", "next"=>"/hangup.json"}}, {"record"=>{"name"=>"foo", "say"=>[{"value"=>"Please say your account number"}], "beep"=>true, "url"=>"http://sendme.com/tropo", "sendTones"=>false, "exitTone"=>"#", "choices"=>{"value"=>"[5 DIGITS]"}}}]}
|
403
|
+
tropo.reset
|
404
|
+
tropo.response.should == "{\"tropo\":[]}"
|
405
|
+
end
|
406
|
+
|
407
|
+
it "should build a Ruby hash object when a session arrives in JSON with a proper Ruby Time object" do
|
408
|
+
json_session = "{\"session\":{\"id\":\"dih06n\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:48.562Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"tropomessaging@bot.im\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"},\"from\":{\"id\":\"john_doe@gmail.com\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"}}}"
|
409
|
+
hash = Tropo::Generator.parse(json_session)
|
410
|
+
hash[:session][:timestamp].should == Time.parse("2010-01-19T23:18:48.562Z")
|
411
|
+
end
|
412
|
+
|
413
|
+
it "should build a Ruby hash object when a result arrives in JSON with one action returned in an array" do
|
414
|
+
json_result = "{\"result\":{\"sessionId\":\"CCFD9C86-1DD1-11B2-B76D-B9B253E4B7FB@161.253.55.20\",\"callState\":\"ANSWERED\",\"sessionDuration\":2,\"sequence\":1,\"complete\":true,\"error\":null,\"actions\":{\"name\":\"zip\",\"attempts\":1,\"disposition\":\"SUCCESS\",\"confidence\":100,\"interpretation\":\"12345\",\"utterance\":\"1 2 3 4 5\"}}}"
|
415
|
+
hash = Tropo::Generator.parse(json_result)
|
416
|
+
hash.should == Hashie::Mash.new({:result=>{:call_state=>"ANSWERED", :complete=>true, :actions=>{:zip=>{:utterance=>"1 2 3 4 5", :attempts=>1, :interpretation=>"12345", :confidence=>100, :disposition=>"SUCCESS"}}, :session_id=>"CCFD9C86-1DD1-11B2-B76D-B9B253E4B7FB@161.253.55.20", :session_duration=>2, :error=>nil, :sequence=>1}})
|
417
|
+
end
|
418
|
+
|
419
|
+
it "should build a Hashie object when a result arrives in JSON" do
|
420
|
+
json_result = "{\"result\":{\"sessionId\":\"CCFD9C86-1DD1-11B2-B76D-B9B253E4B7FB@161.253.55.20\",\"callState\":\"ANSWERED\",\"sessionDuration\":2,\"sequence\":1,\"complete\":true,\"error\":null,\"actions\":{\"name\":\"zip\",\"attempts\":1,\"disposition\":\"SUCCESS\",\"confidence\":100,\"interpretation\":\"12345\",\"utterance\":\"1 2 3 4 5\"}}}"
|
421
|
+
hash = Tropo::Generator.parse(json_result)
|
422
|
+
hash.result.call_state.should == 'ANSWERED'
|
423
|
+
hash[:result][:call_state].should == 'ANSWERED'
|
424
|
+
hash['result']['call_state'].should == 'ANSWERED'
|
425
|
+
end
|
426
|
+
|
427
|
+
it "should generate valid JSON when a startRecording is used" do
|
428
|
+
t = Tropo::Generator.new
|
429
|
+
t.on :event => 'error', :next => '/error.json' # For fatal programming errors. Log some details so we can fix it
|
430
|
+
t.on :event => 'hangup', :next => '/hangup.json' # When a user hangs or call is done. We will want to log some details.
|
431
|
+
t.on :event => 'continue', :next => '/next.json'
|
432
|
+
t.say "Hello"
|
433
|
+
t.start_recording(:url => "http://heroku-voip.marksilver.net/post_audio_to_s3?filename=foo.wav&unique_id=bar")
|
434
|
+
# [From this point, until stop_recording(), we will record what the caller *and* the IVR say]
|
435
|
+
t.say "You are now on the record."
|
436
|
+
# Prompt the user to incriminate themselve on-the-record
|
437
|
+
t.say "Go ahead, sing-along."
|
438
|
+
t.say "http://denalidomain.com/music/keepers/HappyHappyBirthdaytoYou-Disney.mp3"
|
439
|
+
JSON.parse(t.response).should == {"tropo"=>[{"on"=>{"event"=>"error", "next"=>"/error.json"}}, {"on"=>{"event"=>"hangup", "next"=>"/hangup.json"}}, {"on"=>{"event"=>"continue", "next"=>"/next.json"}}, {"say"=>[{"value"=>"Hello"}]}, {"startRecording"=>{"url"=>"http://heroku-voip.marksilver.net/post_audio_to_s3?filename=foo.wav&unique_id=bar"}}, {"say"=>[{"value"=>"You are now on the record."}]}, {"say"=>[{"value"=>"Go ahead, sing-along."}]}, {"say"=>[{"value"=>"http://denalidomain.com/music/keepers/HappyHappyBirthdaytoYou-Disney.mp3"}]}]}
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should generate a voice_session true if a JSON session is received that is a channel of 'VOICE'" do
|
443
|
+
tropo = Tropo::Generator.new
|
444
|
+
tropo.parse "{\"session\":{\"id\":\"0-13c4-4b563da3-7aecefda-46af-1d10bdd0\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:00.854Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"9991427589\",\"name\":\"unknown\",\"channel\":\"VOICE\",\"network\":\"PSTN\"},\"from\":{\"id\":\"jsgoecke\",\"name\":\"unknown\",\"channel\":\"VOICE\",\"network\":\"PSTN\"}}}"
|
445
|
+
tropo.voice_session.should == true
|
446
|
+
tropo.text_session.should == false
|
447
|
+
end
|
448
|
+
|
449
|
+
it "should generate a text_session true if a JSON session is received that is a channel of 'TEXT'" do
|
450
|
+
tropo = Tropo::Generator.new
|
451
|
+
tropo.parse "{\"session\":{\"id\":\"dih06n\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:48.562Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"tropomessaging@bot.im\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"},\"from\":{\"id\":\"john_doe@gmail.com\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"}}}"
|
452
|
+
tropo.voice_session.should == false
|
453
|
+
tropo.text_session.should == true
|
454
|
+
end
|
455
|
+
|
456
|
+
it "should generate a valid JSON string for a call method" do
|
457
|
+
json_result = "{\"tropo\":[{\"call\":{\"recording\":{\"password\":\"passwd\",\"username\":\"jose\",\"method\":\"POST\",\"url\":\"http://foobar\",\"format\":\"audio/mp3\"},\"timeout\":10,\"network\":\"SMS\",\"channel\":\"TEXT\",\"to\":\"foo\",\"from\":\"bar\",\"headers\":{\"foo\":\"foo\",\"bar\":\"bar\"},\"answerOnMedia\":false}}]}"
|
458
|
+
tropo = Tropo::Generator.call({ :to => 'foo',
|
459
|
+
:from => 'bar',
|
460
|
+
:network => 'SMS',
|
461
|
+
:channel => 'TEXT',
|
462
|
+
:timeout => 10,
|
463
|
+
:answer_on_media => false,
|
464
|
+
:headers => { :foo => 'foo', :bar => 'bar' },
|
465
|
+
:recording => { :url => 'http://foobar',
|
466
|
+
:method => 'POST',
|
467
|
+
:format => 'audio/mp3',
|
468
|
+
:username => 'jose',
|
469
|
+
:password => 'passwd' } })
|
470
|
+
JSON.parse(tropo).should == JSON.parse(json_result)
|
471
|
+
end
|
472
|
+
|
473
|
+
it "should generate a valid JSON string for a message method" do
|
474
|
+
hash_result = {"tropo"=>[{"message"=>{"say"=>[{"value"=>"Please say your account number"}], "from"=>"bar", "timeout"=>10, "to"=>"foo", "network"=>"SMS", "answerOnMedia"=>false, "channel"=>"TEXT", "recording"=>{"format"=>"audio/mp3", "method"=>"POST", "url"=>"http://foobar", "username"=>"jose", "password"=>"passwd"}, "headers"=>{"foo"=>"foo", "bar"=>"bar"}}}]}
|
475
|
+
tropo = Tropo::Generator.message({ :to => 'foo',
|
476
|
+
:from => 'bar',
|
477
|
+
:network => 'SMS',
|
478
|
+
:channel => 'TEXT',
|
479
|
+
:timeout => 10,
|
480
|
+
:answer_on_media => false,
|
481
|
+
:headers => { :foo => 'foo', :bar => 'bar' },
|
482
|
+
:recording => { :url => 'http://foobar',
|
483
|
+
:method => 'POST',
|
484
|
+
:format => 'audio/mp3',
|
485
|
+
:username => 'jose',
|
486
|
+
:password => 'passwd' } }) do
|
487
|
+
say :value => 'Please say your account number'
|
488
|
+
end
|
489
|
+
JSON.parse(tropo).should == hash_result
|
490
|
+
end
|
491
|
+
|
492
|
+
it "should generate a valid JSON string for a record method with a transcription request" do
|
493
|
+
hash_result = {"tropo"=>[{"record"=>{"name"=>"foo", "transcription"=>{"email_format"=>"encoded", "url"=>"mailto:jose@voxeo.com", "id"=>"bling"}, "say"=>[{"value"=>"Please say your account number"}], "beep"=>true, "url"=>"http://sendme.com/tropo", "exitTone"=>"#", "sendTones"=>false, "choices"=>{"value"=>"[5 DIGITS]"}}}]}
|
494
|
+
tropo = Tropo::Generator.record({ :name => 'foo',
|
495
|
+
:url => 'http://sendme.com/tropo',
|
496
|
+
:beep => true,
|
497
|
+
:send_tones => false,
|
498
|
+
:transcription => { :id => 'bling',
|
499
|
+
:url => 'mailto:jose@voxeo.com',
|
500
|
+
:email_format => 'encoded' },
|
501
|
+
:exit_tone => '#' }) do
|
502
|
+
say :value => 'Please say your account number'
|
503
|
+
choices :value => '[5 DIGITS]'
|
504
|
+
end
|
505
|
+
JSON.parse(tropo).should == hash_result
|
506
|
+
end
|
507
|
+
|
508
|
+
it "should properly generate a JSON document when calling an ask with says as hash elements rather than as methods" do
|
509
|
+
hash_result = {"tropo"=>[{"ask"=>{"name"=>"donate_to_id", "say"=>[{"event"=>"timeout", "value"=>"Sorry, I did not hear anything."}, {"event"=>"nomatch:1 nomatch:2 nomatch:3", "value"=>"Sorry, that wasn't a valid answer. You can press or say 1 for 'yes', or 2 for 'no'."}, {"value"=>"You chose organization foobar. Are you ready to donate to them? If you say no, I will tell you a little more about the organization."}, {"event"=>"nomatch:3", "value"=>"This is your last attempt."}], "bargein"=>true, "silenceTimeout"=>10, "timeout"=>10, "attempts"=>4, "choices"=>{"value"=>"true(1,yes,sure,affirmative), false(2,no,no thank you,negative), 0(0,help,i do not know, agent, operator, assistance, representative, real person, human), 9(9,quit,stop,shut up)"}}}]}
|
510
|
+
help_stop_choices = "0(0,help,i do not know, agent, operator, assistance, representative, real person, human), 9(9,quit,stop,shut up)"
|
511
|
+
yes_no_choices = "true(1,yes,sure,affirmative), false(2,no,no thank you,negative), " + help_stop_choices
|
512
|
+
|
513
|
+
t = Tropo::Generator.new
|
514
|
+
t.ask :name => 'donate_to_id',
|
515
|
+
:bargein => true,
|
516
|
+
:timeout => 10,
|
517
|
+
:silence_timeout => 10,
|
518
|
+
:attempts => 4,
|
519
|
+
:say => [{:event => "timeout", :value => "Sorry, I did not hear anything."},
|
520
|
+
{:event => "nomatch:1 nomatch:2 nomatch:3", :value => "Sorry, that wasn't a valid answer. You can press or say 1 for 'yes', or 2 for 'no'."},
|
521
|
+
{:value => "You chose organization foobar. Are you ready to donate to them? If you say no, I will tell you a little more about the organization."},
|
522
|
+
{:event => "nomatch:3", :value => "This is your last attempt."}],
|
523
|
+
:choices => { :value => yes_no_choices}
|
524
|
+
JSON.parse(t.response).should == hash_result
|
525
|
+
end
|
526
|
+
|
527
|
+
it "should set the voice variable when called" do
|
528
|
+
t = Tropo::Generator.new
|
529
|
+
t.voice.should == nil
|
530
|
+
|
531
|
+
t = Tropo::Generator.new(:voice => 'barnie')
|
532
|
+
t.voice.should == 'barnie'
|
533
|
+
|
534
|
+
t = Tropo::Generator.new
|
535
|
+
t.voice = 'barnie'
|
536
|
+
t.voice.should == 'barnie'
|
537
|
+
end
|
538
|
+
|
539
|
+
it "should handle the setting of the voice parameter based on defaults" do
|
540
|
+
t = Tropo::Generator.new
|
541
|
+
t.say 'Hi there!'
|
542
|
+
JSON.parse(t.response)['tropo'][0]['say'][0]['voice'].should == nil
|
543
|
+
|
544
|
+
t = Tropo::Generator.new
|
545
|
+
t.say 'Hi there!', :voice => 'barnie'
|
546
|
+
JSON.parse(t.response)['tropo'][0]['say'][0]['voice'].should == 'barnie'
|
547
|
+
|
548
|
+
t = Tropo::Generator.new(:voice => 'barnie')
|
549
|
+
t.say 'Hi there!'
|
550
|
+
t.say 'Wow!'
|
551
|
+
JSON.parse(t.response)['tropo'][0]['say'][0]['voice'].should == 'barnie'
|
552
|
+
JSON.parse(t.response)['tropo'][1]['say'][0]['voice'].should == 'barnie'
|
553
|
+
|
554
|
+
t = Tropo::Generator.new(:voice => 'barnie')
|
555
|
+
t.say 'Hi there!'
|
556
|
+
t.say 'Wow!', :voice => 'jack'
|
557
|
+
JSON.parse(t.response)['tropo'][0]['say'][0]['voice'].should == 'barnie'
|
558
|
+
JSON.parse(t.response)['tropo'][1]['say'][0]['voice'].should == 'jack'
|
559
|
+
|
560
|
+
t = Tropo::Generator.new
|
561
|
+
t.voice = 'barnie'
|
562
|
+
t.say 'Hi there!'
|
563
|
+
t.say 'Wow!', :voice => 'jack'
|
564
|
+
JSON.parse(t.response)['tropo'][0]['say'][0]['voice'].should == 'barnie'
|
565
|
+
JSON.parse(t.response)['tropo'][1]['say'][0]['voice'].should == 'jack'
|
566
|
+
end
|
567
|
+
|
568
|
+
it "should set the recognizer variable when called" do
|
569
|
+
t = Tropo::Generator.new
|
570
|
+
t.recognizer.should == nil
|
571
|
+
|
572
|
+
t = Tropo::Generator.new(:recognizer => 'fr-fr')
|
573
|
+
t.recognizer.should == 'fr-fr'
|
574
|
+
|
575
|
+
t = Tropo::Generator.new
|
576
|
+
t.recognizer = 'fr-fr'
|
577
|
+
t.recognizer.should == 'fr-fr'
|
578
|
+
end
|
579
|
+
|
580
|
+
it "should handle the setting of the recognizer parameter based on defaults" do
|
581
|
+
t = Tropo::Generator.new
|
582
|
+
t.ask({ :name => 'foo',
|
583
|
+
:bargein => 'true',
|
584
|
+
:timeout => 30,
|
585
|
+
:require => 'true' })
|
586
|
+
JSON.parse(t.response)['tropo'][0]['ask']['recognizer'].should == nil
|
587
|
+
|
588
|
+
t = Tropo::Generator.new(:recognizer => 'fr-fr')
|
589
|
+
t.ask({ :name => 'foo',
|
590
|
+
:bargein => 'true',
|
591
|
+
:timeout => 30,
|
592
|
+
:require => 'true' })
|
593
|
+
JSON.parse(t.response)['tropo'][0]['ask']['recognizer'].should == 'fr-fr'
|
594
|
+
|
595
|
+
t = Tropo::Generator.new
|
596
|
+
t.recognizer = 'fr-fr'
|
597
|
+
t.ask({ :name => 'foo',
|
598
|
+
:bargein => 'true',
|
599
|
+
:timeout => 30,
|
600
|
+
:require => 'true' })
|
601
|
+
JSON.parse(t.response)['tropo'][0]['ask']['recognizer'].should == 'fr-fr'
|
602
|
+
|
603
|
+
t = Tropo::Generator.new
|
604
|
+
t.recognizer = 'fr-fr'
|
605
|
+
t.ask({ :name => 'foo',
|
606
|
+
:bargein => 'true',
|
607
|
+
:timeout => 30,
|
608
|
+
:require => 'true' })
|
609
|
+
t.ask({ :name => 'foo',
|
610
|
+
:bargein => 'true',
|
611
|
+
:timeout => 30,
|
612
|
+
:require => 'true',
|
613
|
+
:recognizer => 'de-de' })
|
614
|
+
JSON.parse(t.response)['tropo'][0]['ask']['recognizer'].should == 'fr-fr'
|
615
|
+
JSON.parse(t.response)['tropo'][1]['ask']['recognizer'].should == 'de-de'
|
616
|
+
end
|
617
|
+
|
618
|
+
it "should parse a JSON string or a Ruby Hash the same" do
|
619
|
+
json_session = "{\"session\":{\"id\":\"dih06n\",\"accountId\":\"33932\",\"timestamp\":\"2010-01-19T23:18:48.562Z\",\"userType\":\"HUMAN\",\"to\":{\"id\":\"tropomessaging@bot.im\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"},\"from\":{\"id\":\"john_doe@gmail.com\",\"name\":\"unknown\",\"channel\":\"TEXT\",\"network\":\"JABBER\"}}}"
|
620
|
+
tropo = Tropo::Generator.parse json_session
|
621
|
+
tropo.session.user_type.should == 'HUMAN'
|
622
|
+
|
623
|
+
tropo = Tropo::Generator.parse(JSON.parse(json_session))
|
624
|
+
tropo.session.user_type.should == 'HUMAN'
|
625
|
+
end
|
626
|
+
|
627
|
+
it "should return a hash of the response object" do
|
628
|
+
result = Tropo::Generator.new do
|
629
|
+
say [{ :value => '1234' }, { :value => 'abcd', :event => "nomatch:1" }]
|
630
|
+
say [{ :value => '0987' }, { :value => 'zyxw', :event => "nomatch:2" }]
|
631
|
+
end
|
632
|
+
result.to_hash.should == { :tropo => [{ :say => [{ :value => "1234" },
|
633
|
+
{ :event => "nomatch:1", :value => "abcd" }] },
|
634
|
+
{ :say => [{ :value => "0987" },
|
635
|
+
{ :event => "nomatch:2", :value => "zyxw" }] }] }
|
636
|
+
end
|
637
|
+
end
|