adhearsion 2.6.4 → 3.0.0.beta1

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 (242) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +6 -9
  3. data/CHANGELOG.md +22 -7
  4. data/Gemfile +2 -0
  5. data/README.markdown +4 -5
  6. data/Rakefile +1 -2
  7. data/adhearsion.gemspec +19 -8
  8. data/features/cli_create.feature +19 -3
  9. data/features/step_definitions/cli_steps.rb +0 -11
  10. data/features/support/env.rb +3 -4
  11. data/lib/adhearsion.rb +48 -27
  12. data/lib/adhearsion/call.rb +34 -50
  13. data/lib/adhearsion/call_controller.rb +6 -12
  14. data/lib/adhearsion/call_controller/dial.rb +15 -53
  15. data/lib/adhearsion/call_controller/input.rb +39 -162
  16. data/lib/adhearsion/call_controller/input/ask_grammar_builder.rb +44 -0
  17. data/lib/adhearsion/call_controller/input/menu_builder.rb +136 -0
  18. data/lib/adhearsion/call_controller/input/prompt_builder.rb +78 -0
  19. data/lib/adhearsion/call_controller/input/result.rb +46 -0
  20. data/lib/adhearsion/call_controller/output.rb +48 -67
  21. data/lib/adhearsion/call_controller/output/abstract_player.rb +3 -3
  22. data/lib/adhearsion/call_controller/output/async_player.rb +3 -3
  23. data/lib/adhearsion/call_controller/output/player.rb +1 -1
  24. data/lib/adhearsion/call_controller/record.rb +23 -8
  25. data/lib/adhearsion/calls.rb +1 -1
  26. data/lib/adhearsion/cli_commands/ahn_command.rb +2 -65
  27. data/lib/adhearsion/cli_commands/thor_errors.rb +0 -6
  28. data/lib/adhearsion/configuration.rb +91 -39
  29. data/lib/adhearsion/core_ext/blather/stanza.rb +41 -0
  30. data/lib/adhearsion/core_ext/blather/stanza/presence.rb +13 -0
  31. data/lib/adhearsion/error.rb +5 -0
  32. data/lib/adhearsion/event.rb +21 -0
  33. data/lib/adhearsion/event/active_speaker.rb +11 -0
  34. data/lib/adhearsion/event/answered.rb +11 -0
  35. data/lib/adhearsion/event/asterisk.rb +10 -0
  36. data/lib/adhearsion/event/asterisk/ami.rb +34 -0
  37. data/lib/adhearsion/event/complete.rb +75 -0
  38. data/lib/adhearsion/event/dtmf.rb +11 -0
  39. data/lib/adhearsion/event/end.rb +22 -0
  40. data/lib/adhearsion/event/input_timers_started.rb +9 -0
  41. data/lib/adhearsion/event/joined.rb +17 -0
  42. data/lib/adhearsion/event/offer.rb +14 -0
  43. data/lib/adhearsion/event/ringing.rb +11 -0
  44. data/lib/adhearsion/event/started_speaking.rb +13 -0
  45. data/lib/adhearsion/event/stopped_speaking.rb +13 -0
  46. data/lib/adhearsion/event/unjoined.rb +17 -0
  47. data/lib/adhearsion/events.rb +47 -66
  48. data/lib/adhearsion/foundation.rb +0 -1
  49. data/lib/adhearsion/foundation/object.rb +0 -5
  50. data/lib/adhearsion/generators/app/app_generator.rb +4 -1
  51. data/lib/adhearsion/generators/app/templates/Gemfile.erb +2 -10
  52. data/lib/adhearsion/generators/app/templates/adhearsion.erb +9 -9
  53. data/lib/adhearsion/generators/app/templates/config.ru +7 -0
  54. data/lib/adhearsion/generators/app/templates/en.yml +4 -0
  55. data/lib/adhearsion/generators/app/templates/events.erb +2 -2
  56. data/lib/adhearsion/generators/app/templates/hello_world.wav +0 -0
  57. data/lib/adhearsion/generators/app/templates/simon_game.rb +2 -1
  58. data/lib/adhearsion/generators/app/templates/simon_game_spec.rb +2 -2
  59. data/lib/adhearsion/has_headers.rb +34 -0
  60. data/lib/adhearsion/http_server.rb +37 -0
  61. data/lib/adhearsion/initializer.rb +19 -153
  62. data/lib/adhearsion/logging.rb +6 -25
  63. data/lib/adhearsion/outbound_call.rb +5 -5
  64. data/lib/adhearsion/plugin.rb +1 -0
  65. data/lib/adhearsion/protocol_error.rb +26 -0
  66. data/lib/adhearsion/rayo.rb +30 -0
  67. data/lib/adhearsion/rayo/client.rb +62 -0
  68. data/lib/adhearsion/rayo/client/component_registry.rb +33 -0
  69. data/lib/adhearsion/rayo/command.rb +21 -0
  70. data/lib/adhearsion/rayo/command/accept.rb +16 -0
  71. data/lib/adhearsion/rayo/command/answer.rb +16 -0
  72. data/lib/adhearsion/rayo/command/dial.rb +57 -0
  73. data/lib/adhearsion/rayo/command/hangup.rb +16 -0
  74. data/lib/adhearsion/rayo/command/join.rb +43 -0
  75. data/lib/adhearsion/rayo/command/mute.rb +13 -0
  76. data/lib/adhearsion/rayo/command/redirect.rb +23 -0
  77. data/lib/adhearsion/rayo/command/reject.rb +40 -0
  78. data/lib/adhearsion/rayo/command/unjoin.rb +24 -0
  79. data/lib/adhearsion/rayo/command/unmute.rb +13 -0
  80. data/lib/adhearsion/rayo/command_node.rb +47 -0
  81. data/lib/adhearsion/rayo/component.rb +21 -0
  82. data/lib/adhearsion/rayo/component/asterisk.rb +13 -0
  83. data/lib/adhearsion/rayo/component/asterisk/agi.rb +14 -0
  84. data/lib/adhearsion/rayo/component/asterisk/agi/command.rb +46 -0
  85. data/lib/adhearsion/rayo/component/asterisk/ami.rb +14 -0
  86. data/lib/adhearsion/rayo/component/asterisk/ami/action.rb +61 -0
  87. data/lib/adhearsion/rayo/component/component_node.rb +90 -0
  88. data/lib/adhearsion/rayo/component/input.rb +186 -0
  89. data/lib/adhearsion/rayo/component/output.rb +471 -0
  90. data/lib/adhearsion/rayo/component/prompt.rb +53 -0
  91. data/lib/adhearsion/rayo/component/receive_fax.rb +26 -0
  92. data/lib/adhearsion/rayo/component/record.rb +165 -0
  93. data/lib/adhearsion/rayo/component/send_fax.rb +64 -0
  94. data/lib/adhearsion/rayo/component/stop.rb +11 -0
  95. data/lib/adhearsion/rayo/connection.rb +12 -0
  96. data/lib/adhearsion/rayo/connection/asterisk.rb +74 -0
  97. data/lib/adhearsion/rayo/connection/connected.rb +22 -0
  98. data/lib/adhearsion/rayo/connection/generic_connection.rb +22 -0
  99. data/lib/adhearsion/rayo/connection/xmpp.rb +198 -0
  100. data/lib/adhearsion/rayo/disconnected_error.rb +22 -0
  101. data/lib/adhearsion/{punchblock_plugin → rayo}/initializer.rb +19 -19
  102. data/lib/adhearsion/rayo/rayo_node.rb +127 -0
  103. data/lib/adhearsion/rayo/ref.rb +57 -0
  104. data/lib/adhearsion/statistics.rb +1 -1
  105. data/lib/adhearsion/tasks.rb +1 -2
  106. data/lib/adhearsion/tasks/configuration.rb +1 -1
  107. data/lib/adhearsion/tasks/environment.rb +0 -2
  108. data/lib/adhearsion/tasks/i18n.rb +49 -0
  109. data/lib/adhearsion/translator.rb +11 -0
  110. data/lib/adhearsion/translator/asterisk.rb +234 -0
  111. data/lib/adhearsion/translator/asterisk/agi_app.rb +17 -0
  112. data/lib/adhearsion/translator/asterisk/agi_command.rb +45 -0
  113. data/lib/adhearsion/translator/asterisk/ami_error_converter.rb +20 -0
  114. data/lib/adhearsion/translator/asterisk/call.rb +416 -0
  115. data/lib/adhearsion/translator/asterisk/channel.rb +43 -0
  116. data/lib/adhearsion/translator/asterisk/component.rb +88 -0
  117. data/lib/adhearsion/translator/asterisk/component/asterisk.rb +15 -0
  118. data/lib/adhearsion/translator/asterisk/component/asterisk/agi_command.rb +42 -0
  119. data/lib/adhearsion/translator/asterisk/component/asterisk/ami_action.rb +68 -0
  120. data/lib/adhearsion/translator/asterisk/component/composed_prompt.rb +76 -0
  121. data/lib/adhearsion/translator/asterisk/component/dtmf_recognizer.rb +137 -0
  122. data/lib/adhearsion/translator/asterisk/component/input.rb +34 -0
  123. data/lib/adhearsion/translator/asterisk/component/input_component.rb +90 -0
  124. data/lib/adhearsion/translator/asterisk/component/mrcp_native_prompt.rb +71 -0
  125. data/lib/adhearsion/translator/asterisk/component/mrcp_prompt.rb +55 -0
  126. data/lib/adhearsion/translator/asterisk/component/mrcp_recog_prompt.rb +165 -0
  127. data/lib/adhearsion/translator/asterisk/component/output.rb +233 -0
  128. data/lib/adhearsion/translator/asterisk/component/record.rb +101 -0
  129. data/lib/adhearsion/translator/asterisk/component/stop_by_redirect.rb +30 -0
  130. data/lib/adhearsion/translator/asterisk/unimrcp_app.rb +28 -0
  131. data/lib/adhearsion/uri_list.rb +21 -0
  132. data/lib/adhearsion/version.rb +1 -1
  133. data/spec/adhearsion/call_controller/dial_spec.rb +79 -1420
  134. data/spec/adhearsion/call_controller/input_spec.rb +1141 -237
  135. data/spec/adhearsion/call_controller/output/async_player_spec.rb +10 -10
  136. data/spec/adhearsion/call_controller/output/player_spec.rb +8 -8
  137. data/spec/adhearsion/call_controller/output_spec.rb +162 -215
  138. data/spec/adhearsion/call_controller/record_spec.rb +15 -16
  139. data/spec/adhearsion/call_controller_spec.rb +23 -40
  140. data/spec/adhearsion/call_spec.rb +123 -129
  141. data/spec/adhearsion/calls_spec.rb +3 -3
  142. data/spec/adhearsion/configuration_spec.rb +94 -108
  143. data/spec/adhearsion/event/answered_spec.rb +50 -0
  144. data/spec/adhearsion/event/asterisk/Find Results +402 -0
  145. data/spec/adhearsion/event/asterisk/ami_spec.rb +81 -0
  146. data/spec/adhearsion/event/complete_spec.rb +176 -0
  147. data/spec/adhearsion/event/dtmf_spec.rb +35 -0
  148. data/spec/adhearsion/event/end_spec.rb +85 -0
  149. data/spec/adhearsion/event/input_timers_started_spec.rb +19 -0
  150. data/spec/adhearsion/event/joined_spec.rb +53 -0
  151. data/spec/adhearsion/event/offer_spec.rb +106 -0
  152. data/spec/adhearsion/event/ringing_spec.rb +50 -0
  153. data/spec/adhearsion/event/started_speaking_spec.rb +37 -0
  154. data/spec/adhearsion/event/stopped_speaking_spec.rb +37 -0
  155. data/spec/adhearsion/event/unjoined_spec.rb +48 -0
  156. data/spec/adhearsion/event/untitled +0 -0
  157. data/spec/adhearsion/events_spec.rb +19 -45
  158. data/spec/adhearsion/initializer_spec.rb +12 -184
  159. data/spec/adhearsion/logging_spec.rb +5 -20
  160. data/spec/adhearsion/outbound_call_spec.rb +13 -13
  161. data/spec/adhearsion/plugin_spec.rb +3 -4
  162. data/spec/adhearsion/protocol_error_spec.rb +91 -0
  163. data/spec/adhearsion/rayo/client/component_registry_spec.rb +26 -0
  164. data/spec/adhearsion/rayo/client_spec.rb +134 -0
  165. data/spec/adhearsion/rayo/command/accept_spec.rb +63 -0
  166. data/spec/adhearsion/rayo/command/answer_spec.rb +73 -0
  167. data/spec/adhearsion/rayo/command/dial_spec.rb +156 -0
  168. data/spec/adhearsion/rayo/command/hangup_spec.rb +63 -0
  169. data/spec/adhearsion/rayo/command/join_spec.rb +158 -0
  170. data/spec/adhearsion/rayo/command/mute_spec.rb +32 -0
  171. data/spec/adhearsion/rayo/command/redirect_spec.rb +89 -0
  172. data/spec/adhearsion/rayo/command/reject_spec.rb +117 -0
  173. data/spec/adhearsion/rayo/command/unjoin_spec.rb +82 -0
  174. data/spec/adhearsion/rayo/command/unmute_spec.rb +32 -0
  175. data/spec/adhearsion/rayo/command_node_spec.rb +101 -0
  176. data/spec/adhearsion/rayo/component/asterisk/agi/command_spec.rb +111 -0
  177. data/spec/adhearsion/rayo/component/asterisk/ami/action_spec.rb +173 -0
  178. data/spec/adhearsion/rayo/component/component_node_spec.rb +110 -0
  179. data/spec/adhearsion/rayo/component/input_spec.rb +715 -0
  180. data/spec/adhearsion/rayo/component/output_spec.rb +1030 -0
  181. data/spec/adhearsion/rayo/component/prompt_spec.rb +171 -0
  182. data/spec/adhearsion/rayo/component/receive_fax_spec.rb +136 -0
  183. data/spec/adhearsion/rayo/component/record_spec.rb +497 -0
  184. data/spec/adhearsion/rayo/component/send_fax_spec.rb +144 -0
  185. data/spec/adhearsion/rayo/connection/asterisk_spec.rb +118 -0
  186. data/spec/adhearsion/rayo/connection/xmpp_spec.rb +449 -0
  187. data/spec/adhearsion/rayo/initializer_spec.rb +353 -0
  188. data/spec/adhearsion/rayo/ref_spec.rb +168 -0
  189. data/spec/adhearsion/rayo_spec.rb +7 -0
  190. data/spec/adhearsion/router/route_spec.rb +1 -1
  191. data/spec/adhearsion/statistics_spec.rb +2 -5
  192. data/spec/adhearsion/translator/asterisk/call_spec.rb +2047 -0
  193. data/spec/adhearsion/translator/asterisk/component/asterisk/agi_command_spec.rb +256 -0
  194. data/spec/adhearsion/translator/asterisk/component/asterisk/ami_action_spec.rb +151 -0
  195. data/spec/adhearsion/translator/asterisk/component/composed_prompt_spec.rb +257 -0
  196. data/spec/adhearsion/translator/asterisk/component/input_spec.rb +571 -0
  197. data/spec/adhearsion/translator/asterisk/component/mrcp_native_prompt_spec.rb +774 -0
  198. data/spec/adhearsion/translator/asterisk/component/mrcp_prompt_spec.rb +1244 -0
  199. data/spec/adhearsion/translator/asterisk/component/output_spec.rb +1850 -0
  200. data/spec/adhearsion/translator/asterisk/component/record_spec.rb +426 -0
  201. data/spec/adhearsion/translator/asterisk/component/stop_by_redirect_spec.rb +62 -0
  202. data/spec/adhearsion/translator/asterisk/component_spec.rb +83 -0
  203. data/spec/adhearsion/translator/asterisk_spec.rb +685 -0
  204. data/spec/adhearsion/uri_list_spec.rb +88 -0
  205. data/spec/adhearsion_spec.rb +89 -14
  206. data/spec/fixtures/locale/en.yml +13 -0
  207. data/spec/fixtures/locale/it.yml +13 -0
  208. data/spec/spec_helper.rb +18 -5
  209. data/spec/support/call_controller_test_helpers.rb +3 -2
  210. data/spec/support/initializer_stubs.rb +3 -1
  211. data/spec/support/punchblock_examples.rb +65 -0
  212. data/spec/support/punchblock_mocks.rb +12 -0
  213. metadata +412 -70
  214. data/features/cli_daemon.feature +0 -20
  215. data/features/cli_restart.feature +0 -52
  216. data/features/cli_stop.feature +0 -50
  217. data/lib/adhearsion/call_controller/menu_dsl.rb +0 -21
  218. data/lib/adhearsion/call_controller/menu_dsl/array_match_calculator.rb +0 -26
  219. data/lib/adhearsion/call_controller/menu_dsl/calculated_match.rb +0 -43
  220. data/lib/adhearsion/call_controller/menu_dsl/calculated_match_collection.rb +0 -45
  221. data/lib/adhearsion/call_controller/menu_dsl/fixnum_match_calculator.rb +0 -11
  222. data/lib/adhearsion/call_controller/menu_dsl/match_calculator.rb +0 -40
  223. data/lib/adhearsion/call_controller/menu_dsl/menu.rb +0 -207
  224. data/lib/adhearsion/call_controller/menu_dsl/menu_builder.rb +0 -92
  225. data/lib/adhearsion/call_controller/menu_dsl/range_match_calculator.rb +0 -60
  226. data/lib/adhearsion/call_controller/menu_dsl/string_match_calculator.rb +0 -25
  227. data/lib/adhearsion/call_controller/utility.rb +0 -77
  228. data/lib/adhearsion/foundation/custom_daemonizer.rb +0 -52
  229. data/lib/adhearsion/punchblock_plugin.rb +0 -63
  230. data/scripts/cloc-1.64.pl +0 -10483
  231. data/spec/adhearsion/call_controller/menu_dsl/array_match_calculator_spec.rb +0 -76
  232. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_collection_spec.rb +0 -60
  233. data/spec/adhearsion/call_controller/menu_dsl/calculated_match_spec.rb +0 -61
  234. data/spec/adhearsion/call_controller/menu_dsl/fixnum_match_calculator_spec.rb +0 -39
  235. data/spec/adhearsion/call_controller/menu_dsl/match_calculator_spec.rb +0 -17
  236. data/spec/adhearsion/call_controller/menu_dsl/menu_builder_spec.rb +0 -165
  237. data/spec/adhearsion/call_controller/menu_dsl/menu_spec.rb +0 -420
  238. data/spec/adhearsion/call_controller/menu_dsl/range_match_calculator_spec.rb +0 -32
  239. data/spec/adhearsion/call_controller/menu_dsl/string_match_calculator_spec.rb +0 -40
  240. data/spec/adhearsion/call_controller/utility_spec.rb +0 -90
  241. data/spec/adhearsion/punchblock_plugin/initializer_spec.rb +0 -356
  242. data/spec/adhearsion/punchblock_plugin_spec.rb +0 -59
@@ -0,0 +1,171 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Adhearsion::Rayo::Component::Prompt do
6
+ it 'registers itself' do
7
+ expect(Adhearsion::Rayo::RayoNode.class_from_registration(:prompt, 'urn:xmpp:rayo:prompt:1')).to eq(described_class)
8
+ end
9
+
10
+ describe "when setting options in initializer" do
11
+ let(:output) { Adhearsion::Rayo::Component::Output.new :render_document => {content_type: 'text/uri-list', value: Adhearsion::URIList.new('http://example.com/hello.mp3')} }
12
+ let(:input) { Adhearsion::Rayo::Component::Input.new :mode => :voice }
13
+ subject { described_class.new output, input, :barge_in => true }
14
+
15
+ describe '#output' do
16
+ subject { super().output }
17
+ it { is_expected.to eq(output) }
18
+ end
19
+
20
+ describe '#input' do
21
+ subject { super().input }
22
+ it { is_expected.to eq(input) }
23
+ end
24
+
25
+ describe '#barge_in' do
26
+ subject { super().barge_in }
27
+ it { is_expected.to be_truthy }
28
+ end
29
+
30
+ context "with barge-in unset" do
31
+ subject { described_class.new output, input }
32
+
33
+ describe '#barge_in' do
34
+ subject { super().barge_in }
35
+ it { is_expected.to be_nil }
36
+ end
37
+ end
38
+
39
+ context "with options for sub-components" do
40
+ subject { described_class.new({renderer: :foo}, {recognizer: :bar}) }
41
+
42
+ describe '#output' do
43
+ subject { super().output }
44
+ it { is_expected.to eq(Adhearsion::Rayo::Component::Output.new(renderer: :foo)) }
45
+ end
46
+
47
+ describe '#input' do
48
+ subject { super().input }
49
+ it { is_expected.to eq(Adhearsion::Rayo::Component::Input.new(recognizer: :bar)) }
50
+ end
51
+ end
52
+
53
+ describe "exporting to Rayo" do
54
+ it "should export to XML that can be understood by its parser" do
55
+ new_instance = Adhearsion::Rayo::RayoNode.from_xml subject.to_rayo
56
+ expect(new_instance).to be_instance_of described_class
57
+ expect(new_instance.output).to eq(output)
58
+ expect(new_instance.input).to eq(input)
59
+ expect(new_instance.barge_in).to be_truthy
60
+ end
61
+
62
+ it "should render to a parent node if supplied" do
63
+ doc = Nokogiri::XML::Document.new
64
+ parent = Nokogiri::XML::Node.new 'foo', doc
65
+ doc.root = parent
66
+ rayo_doc = subject.to_rayo(parent)
67
+ expect(rayo_doc).to eq(parent)
68
+ end
69
+ end
70
+ end
71
+
72
+ describe "from a stanza" do
73
+ let :ssml do
74
+ RubySpeech::SSML.draw do
75
+ audio :src => 'http://foo.com/bar.mp3'
76
+ end
77
+ end
78
+
79
+ let :stanza do
80
+ <<-MESSAGE
81
+ <prompt xmlns="urn:xmpp:rayo:prompt:1" barge-in="true">
82
+ <output xmlns="urn:xmpp:rayo:output:1" voice="allison">
83
+ <document content-type="application/ssml+xml">
84
+ <![CDATA[
85
+ <speak version="1.0"
86
+ xmlns="http://www.w3.org/2001/10/synthesis"
87
+ xml:lang="en-US">
88
+ <audio src="http://foo.com/bar.mp3"/>
89
+ </speak>
90
+ ]]>
91
+ </document>
92
+ </output>
93
+ <input xmlns="urn:xmpp:rayo:input:1" mode="voice">
94
+ <grammar content-type="application/grammar+custom">
95
+ <![CDATA[ [5 DIGITS] ]]>
96
+ </grammar>
97
+ </input>
98
+ </prompt>
99
+ MESSAGE
100
+ end
101
+
102
+ subject { Adhearsion::Rayo::RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
103
+
104
+ it { is_expected.to be_instance_of described_class }
105
+
106
+ describe '#barge_in' do
107
+ subject { super().barge_in }
108
+ it { is_expected.to be_truthy }
109
+ end
110
+
111
+ describe '#output' do
112
+ subject { super().output }
113
+ it { is_expected.to eq(Adhearsion::Rayo::Component::Output.new(:voice => 'allison', :render_document => {:value => ssml})) }
114
+ end
115
+
116
+ describe '#input' do
117
+ subject { super().input }
118
+ it { is_expected.to eq(Adhearsion::Rayo::Component::Input.new(:mode => :voice, :grammar => {:value => '[5 DIGITS]', :content_type => 'application/grammar+custom'})) }
119
+ end
120
+ end
121
+
122
+ describe "actions" do
123
+ let(:mock_client) { double 'Client' }
124
+ let(:command) { described_class.new }
125
+
126
+ before do
127
+ command.component_id = 'abc123'
128
+ command.target_call_id = '123abc'
129
+ command.client = mock_client
130
+ end
131
+
132
+ describe '#stop_action' do
133
+ subject { command.stop_action }
134
+
135
+ describe '#to_xml' do
136
+ subject { super().to_xml }
137
+ it { is_expected.to eq('<stop xmlns="urn:xmpp:rayo:ext:1"/>') }
138
+ end
139
+
140
+ describe '#component_id' do
141
+ subject { super().component_id }
142
+ it { is_expected.to eq('abc123') }
143
+ end
144
+
145
+ describe '#target_call_id' do
146
+ subject { super().target_call_id }
147
+ it { is_expected.to eq('123abc') }
148
+ end
149
+ end
150
+
151
+ describe '#stop!' do
152
+ describe "when the command is executing" do
153
+ before do
154
+ command.request!
155
+ command.execute!
156
+ end
157
+
158
+ it "should send its command properly" do
159
+ expect(mock_client).to receive(:execute_command).with(command.stop_action, :target_call_id => '123abc', :component_id => 'abc123')
160
+ command.stop!
161
+ end
162
+ end
163
+
164
+ describe "when the command is not executing" do
165
+ it "should raise an error" do
166
+ expect { command.stop! }.to raise_error(Adhearsion::Rayo::Component::InvalidActionError, "Cannot stop a Prompt that is new")
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
@@ -0,0 +1,136 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Adhearsion::Rayo::Component::ReceiveFax do
6
+ it 'registers itself' do
7
+ expect(Adhearsion::Rayo::RayoNode.class_from_registration(:receivefax, 'urn:xmpp:rayo:fax:1')).to eq(described_class)
8
+ end
9
+
10
+ describe "exporting to Rayo" do
11
+ it "should export to XML that can be understood by its parser" do
12
+ new_instance = Adhearsion::Rayo::RayoNode.from_xml subject.to_rayo
13
+ expect(new_instance).to be_instance_of described_class
14
+ end
15
+
16
+ it "should render to a parent node if supplied" do
17
+ doc = Nokogiri::XML::Document.new
18
+ parent = Nokogiri::XML::Node.new 'foo', doc
19
+ doc.root = parent
20
+ rayo_doc = subject.to_rayo(parent)
21
+ expect(rayo_doc).to eq(parent)
22
+ end
23
+ end
24
+
25
+ describe "from a stanza" do
26
+ let :stanza do
27
+ <<-MESSAGE
28
+ <receivefax xmlns="urn:xmpp:rayo:fax:1"/>
29
+ MESSAGE
30
+ end
31
+
32
+ subject { Adhearsion::Rayo::RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
33
+
34
+ it { is_expected.to be_instance_of described_class }
35
+ end
36
+
37
+ describe "actions" do
38
+ let(:mock_client) { double 'Client' }
39
+ let(:command) { described_class.new }
40
+
41
+ before do
42
+ command.component_id = 'abc123'
43
+ command.target_call_id = '123abc'
44
+ command.client = mock_client
45
+ end
46
+
47
+ describe '#stop_action' do
48
+ subject { command.stop_action }
49
+
50
+ describe '#to_xml' do
51
+ subject { super().to_xml }
52
+ it { is_expected.to eq('<stop xmlns="urn:xmpp:rayo:ext:1"/>') }
53
+ end
54
+
55
+ describe '#component_id' do
56
+ subject { super().component_id }
57
+ it { is_expected.to eq('abc123') }
58
+ end
59
+
60
+ describe '#target_call_id' do
61
+ subject { super().target_call_id }
62
+ it { is_expected.to eq('123abc') }
63
+ end
64
+ end
65
+
66
+ describe '#stop!' do
67
+ describe "when the command is executing" do
68
+ before do
69
+ command.request!
70
+ command.execute!
71
+ end
72
+
73
+ it "should send its command properly" do
74
+ expect(mock_client).to receive(:execute_command).with(command.stop_action, :target_call_id => '123abc', :component_id => 'abc123')
75
+ command.stop!
76
+ end
77
+ end
78
+
79
+ describe "when the command is not executing" do
80
+ it "should raise an error" do
81
+ expect { command.stop! }.to raise_error(Adhearsion::Rayo::Component::InvalidActionError, "Cannot stop a ReceiveFax that is new")
82
+ end
83
+ end
84
+ end
85
+ end
86
+
87
+ describe Adhearsion::Rayo::Component::ReceiveFax::Complete::Finish do
88
+ let :stanza do
89
+ <<-MESSAGE
90
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
91
+ <finish xmlns='urn:xmpp:rayo:fax:complete:1'/>
92
+ <fax xmlns='urn:xmpp:rayo:fax:complete:1' url='http://shakespere.lit/faxes/fax1.tiff' resolution='595x841' size='12287492817' pages='3'/>
93
+ <metadata xmlns='urn:xmpp:rayo:fax:complete:1' name="fax-transfer-rate" value="10000" />
94
+ <metadata xmlns='urn:xmpp:rayo:fax:complete:1' name="foo" value="true" />
95
+ </complete>
96
+ MESSAGE
97
+ end
98
+
99
+ subject(:complete_node) { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root) }
100
+
101
+ it "should understand a finish reason" do
102
+ expect(subject.reason).to be_instance_of described_class
103
+ end
104
+
105
+ describe "should make the fax data available" do
106
+ subject { complete_node.fax }
107
+
108
+ it { is_expected.to be_instance_of Adhearsion::Rayo::Component::ReceiveFax::Fax }
109
+
110
+ describe '#url' do
111
+ subject { super().url }
112
+ it { is_expected.to eq('http://shakespere.lit/faxes/fax1.tiff') }
113
+ end
114
+
115
+ describe '#resolution' do
116
+ subject { super().resolution }
117
+ it { is_expected.to eq('595x841') }
118
+ end
119
+
120
+ describe '#pages' do
121
+ subject { super().pages }
122
+ it { is_expected.to eq(3) }
123
+ end
124
+
125
+ describe '#size' do
126
+ subject { super().size }
127
+ it { is_expected.to eq(12287492817) }
128
+ end
129
+ end
130
+
131
+ describe '#fax_metadata' do
132
+ subject { super().fax_metadata }
133
+ it { is_expected.to eq({'fax-transfer-rate' => '10000', 'foo' => 'true'}) }
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,497 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Adhearsion::Rayo::Component::Record do
6
+ it 'registers itself' do
7
+ expect(Adhearsion::Rayo::RayoNode.class_from_registration(:record, 'urn:xmpp:rayo:record:1')).to eq(described_class)
8
+ end
9
+
10
+ describe "when setting options in initializer" do
11
+ subject(:command) do
12
+ described_class.new :format => 'WAV',
13
+ :start_beep => true,
14
+ :stop_beep => false,
15
+ :start_paused => false,
16
+ :max_duration => 500000,
17
+ :initial_timeout => 10000,
18
+ :final_timeout => 30000,
19
+ :direction => :duplex,
20
+ :mix => true
21
+ end
22
+
23
+ describe '#format' do
24
+ subject { super().format }
25
+ it { is_expected.to eq('WAV') }
26
+ end
27
+
28
+ describe '#start_beep' do
29
+ subject { super().start_beep }
30
+ it { is_expected.to eq(true) }
31
+ end
32
+
33
+ describe '#stop_beep' do
34
+ subject { super().stop_beep }
35
+ it { is_expected.to eq(false) }
36
+ end
37
+
38
+ describe '#start_paused' do
39
+ subject { super().start_paused }
40
+ it { is_expected.to eq(false) }
41
+ end
42
+
43
+ describe '#max_duration' do
44
+ subject { super().max_duration }
45
+ it { is_expected.to eq(500000) }
46
+ end
47
+
48
+ describe '#initial_timeout' do
49
+ subject { super().initial_timeout }
50
+ it { is_expected.to eq(10000) }
51
+ end
52
+
53
+ describe '#final_timeout' do
54
+ subject { super().final_timeout }
55
+ it { is_expected.to eq(30000) }
56
+ end
57
+
58
+ describe '#direction' do
59
+ subject { super().direction }
60
+ it { is_expected.to eq(:duplex) }
61
+ end
62
+
63
+ describe '#mix' do
64
+ subject { super().mix }
65
+ it { is_expected.to eq(true) }
66
+ end
67
+
68
+ describe "exporting to Rayo" do
69
+ it "should export to XML that can be understood by its parser" do
70
+ new_instance = Adhearsion::Rayo::RayoNode.from_xml subject.to_rayo
71
+ expect(new_instance).to be_instance_of described_class
72
+ expect(new_instance.format).to eq('WAV')
73
+ expect(new_instance.start_beep).to eq(true)
74
+ expect(new_instance.stop_beep).to eq(false)
75
+ expect(new_instance.start_paused).to eq(false)
76
+ expect(new_instance.max_duration).to eq(500000)
77
+ expect(new_instance.initial_timeout).to eq(10000)
78
+ expect(new_instance.final_timeout).to eq(30000)
79
+ expect(new_instance.direction).to eq(:duplex)
80
+ expect(new_instance.mix).to eq(true)
81
+ end
82
+
83
+ it "should render to a parent node if supplied" do
84
+ doc = Nokogiri::XML::Document.new
85
+ parent = Nokogiri::XML::Node.new 'foo', doc
86
+ doc.root = parent
87
+ rayo_doc = subject.to_rayo(parent)
88
+ expect(rayo_doc).to eq(parent)
89
+ end
90
+ end
91
+ end
92
+
93
+ describe "from a stanza" do
94
+ let :stanza do
95
+ <<-MESSAGE
96
+ <record xmlns="urn:xmpp:rayo:record:1"
97
+ format="WAV"
98
+ start-beep="true"
99
+ stop-beep="false"
100
+ start-paused="false"
101
+ max-duration="500000"
102
+ initial-timeout="10000"
103
+ direction="duplex"
104
+ mix="true"
105
+ final-timeout="30000"/>
106
+ MESSAGE
107
+ end
108
+
109
+ subject { Adhearsion::Rayo::RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
110
+
111
+ it { is_expected.to be_instance_of described_class }
112
+
113
+ describe '#format' do
114
+ subject { super().format }
115
+ it { is_expected.to eq('WAV') }
116
+ end
117
+
118
+ describe '#start_beep' do
119
+ subject { super().start_beep }
120
+ it { is_expected.to eq(true) }
121
+ end
122
+
123
+ describe '#stop_beep' do
124
+ subject { super().stop_beep }
125
+ it { is_expected.to eq(false) }
126
+ end
127
+
128
+ describe '#start_paused' do
129
+ subject { super().start_paused }
130
+ it { is_expected.to eq(false) }
131
+ end
132
+
133
+ describe '#max_duration' do
134
+ subject { super().max_duration }
135
+ it { is_expected.to eq(500000) }
136
+ end
137
+
138
+ describe '#initial_timeout' do
139
+ subject { super().initial_timeout }
140
+ it { is_expected.to eq(10000) }
141
+ end
142
+
143
+ describe '#final_timeout' do
144
+ subject { super().final_timeout }
145
+ it { is_expected.to eq(30000) }
146
+ end
147
+
148
+ describe '#direction' do
149
+ subject { super().direction }
150
+ it { is_expected.to eq(:duplex) }
151
+ end
152
+
153
+ describe '#mix' do
154
+ subject { super().mix }
155
+ it { is_expected.to eq(true) }
156
+ end
157
+ end
158
+
159
+ describe "with a direction" do
160
+ [nil, :duplex, :send, :recv].each do |direction|
161
+ describe direction.to_s do
162
+ subject { described_class.new :direction => direction }
163
+
164
+ describe '#direction' do
165
+ subject { super().direction }
166
+ it { is_expected.to eq(direction) }
167
+ end
168
+ end
169
+ end
170
+
171
+ describe "no direction" do
172
+ subject { described_class.new }
173
+
174
+ describe '#direction' do
175
+ subject { super().direction }
176
+ it { is_expected.to be_nil }
177
+ end
178
+ end
179
+
180
+ describe "blahblahblah" do
181
+ it "should raise an error" do
182
+ expect { described_class.new(:direction => :blahblahblah) }.to raise_error ArgumentError
183
+ end
184
+ end
185
+ end
186
+
187
+ describe "actions" do
188
+ let(:mock_client) { double 'Client' }
189
+ let(:command) { described_class.new }
190
+
191
+ before do
192
+ command.component_id = 'abc123'
193
+ command.target_call_id = '123abc'
194
+ command.client = mock_client
195
+ end
196
+
197
+ describe '#pause_action' do
198
+ subject { command.pause_action }
199
+
200
+ describe '#to_xml' do
201
+ subject { super().to_xml }
202
+ it { is_expected.to eq('<pause xmlns="urn:xmpp:rayo:record:1"/>') }
203
+ end
204
+
205
+ describe '#component_id' do
206
+ subject { super().component_id }
207
+ it { is_expected.to eq('abc123') }
208
+ end
209
+
210
+ describe '#target_call_id' do
211
+ subject { super().target_call_id }
212
+ it { is_expected.to eq('123abc') }
213
+ end
214
+ end
215
+
216
+ describe '#pause!' do
217
+ describe "when the command is executing" do
218
+ before do
219
+ command.request!
220
+ command.execute!
221
+ end
222
+
223
+ it "should send its command properly" do
224
+ expect(mock_client).to receive(:execute_command).with(command.pause_action, :target_call_id => '123abc', :component_id => 'abc123').and_return true
225
+ expect(command).to receive :paused!
226
+ command.pause!
227
+ end
228
+ end
229
+
230
+ describe "when the command is not executing" do
231
+ it "should raise an error" do
232
+ expect { command.pause! }.to raise_error(Adhearsion::Rayo::Component::InvalidActionError, "Cannot pause a Record that is not executing")
233
+ end
234
+ end
235
+ end
236
+
237
+ describe "#paused!" do
238
+ before do
239
+ command.request!
240
+ command.execute!
241
+ command.paused!
242
+ end
243
+
244
+ describe '#state_name' do
245
+ subject { command.state_name }
246
+ it { is_expected.to eq(:paused) }
247
+ end
248
+
249
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
250
+ expect { subject.paused! }.to raise_error(StateMachine::InvalidTransition)
251
+ end
252
+ end
253
+
254
+ describe '#resume_action' do
255
+ subject { command.resume_action }
256
+
257
+ describe '#to_xml' do
258
+ subject { super().to_xml }
259
+ it { is_expected.to eq('<resume xmlns="urn:xmpp:rayo:record:1"/>') }
260
+ end
261
+
262
+ describe '#component_id' do
263
+ subject { super().component_id }
264
+ it { is_expected.to eq('abc123') }
265
+ end
266
+
267
+ describe '#target_call_id' do
268
+ subject { super().target_call_id }
269
+ it { is_expected.to eq('123abc') }
270
+ end
271
+ end
272
+
273
+ describe '#resume!' do
274
+ describe "when the command is paused" do
275
+ before do
276
+ command.request!
277
+ command.execute!
278
+ command.paused!
279
+ end
280
+
281
+ it "should send its command properly" do
282
+ expect(mock_client).to receive(:execute_command).with(command.resume_action, :target_call_id => '123abc', :component_id => 'abc123').and_return true
283
+ expect(command).to receive :resumed!
284
+ command.resume!
285
+ end
286
+ end
287
+
288
+ describe "when the command is not paused" do
289
+ it "should raise an error" do
290
+ expect { command.resume! }.to raise_error(Adhearsion::Rayo::Component::InvalidActionError, "Cannot resume a Record that is not paused.")
291
+ end
292
+ end
293
+ end
294
+
295
+ describe "#resumed!" do
296
+ before do
297
+ command.request!
298
+ command.execute!
299
+ command.paused!
300
+ command.resumed!
301
+ end
302
+
303
+ describe '#state_name' do
304
+ subject { command.state_name }
305
+ it { is_expected.to eq(:executing) }
306
+ end
307
+
308
+ it "should raise a StateMachine::InvalidTransition when received a second time" do
309
+ expect { subject.resumed! }.to raise_error(StateMachine::InvalidTransition)
310
+ end
311
+ end
312
+
313
+ context "direct recording accessors" do
314
+ let :stanza do
315
+ <<-MESSAGE
316
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
317
+ <success xmlns='urn:xmpp:rayo:record:complete:1'/>
318
+ <recording xmlns='urn:xmpp:rayo:record:complete:1' uri="file:/tmp/rayo7451601434771683422.mp3" duration="34000" size="23450"/>
319
+ </complete>
320
+ MESSAGE
321
+ end
322
+ let(:event) { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root) }
323
+
324
+ before do
325
+ subject.request!
326
+ subject.execute!
327
+ subject.add_event event
328
+ end
329
+
330
+ describe "#recording" do
331
+ it "should be a Adhearsion::Rayo::Component::Record::Recording" do
332
+ expect(subject.recording).to be_a Adhearsion::Rayo::Component::Record::Recording
333
+ end
334
+ end
335
+
336
+ describe "#recording_uri" do
337
+ it "should be the recording URI set earlier" do
338
+ expect(subject.recording_uri).to eq("file:/tmp/rayo7451601434771683422.mp3")
339
+ end
340
+ end
341
+ end
342
+
343
+ describe '#stop_action' do
344
+ subject { command.stop_action }
345
+
346
+ describe '#to_xml' do
347
+ subject { super().to_xml }
348
+ it { is_expected.to eq('<stop xmlns="urn:xmpp:rayo:ext:1"/>') }
349
+ end
350
+
351
+ describe '#component_id' do
352
+ subject { super().component_id }
353
+ it { is_expected.to eq('abc123') }
354
+ end
355
+
356
+ describe '#target_call_id' do
357
+ subject { super().target_call_id }
358
+ it { is_expected.to eq('123abc') }
359
+ end
360
+ end
361
+
362
+ describe '#stop!' do
363
+ describe "when the command is executing" do
364
+ before do
365
+ command.request!
366
+ command.execute!
367
+ end
368
+
369
+ it "should send its command properly" do
370
+ expect(mock_client).to receive(:execute_command).with(command.stop_action, :target_call_id => '123abc', :component_id => 'abc123')
371
+ command.stop!
372
+ end
373
+ end
374
+
375
+ describe "when the command is not executing" do
376
+ it "should raise an error" do
377
+ expect { command.stop! }.to raise_error(Adhearsion::Rayo::Component::InvalidActionError, "Cannot stop a Record that is new")
378
+ end
379
+ end
380
+ end
381
+ end
382
+
383
+ {
384
+ described_class::Complete::MaxDuration => :'max-duration',
385
+ described_class::Complete::InitialTimeout => :'initial-timeout',
386
+ described_class::Complete::FinalTimeout => :'final-timeout',
387
+ }.each do |klass, element_name|
388
+ describe klass do
389
+ let :stanza do
390
+ <<-MESSAGE
391
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
392
+ <#{element_name} xmlns='urn:xmpp:rayo:record:complete:1'/>
393
+ <recording xmlns='urn:xmpp:rayo:record:complete:1' uri="file:/tmp/rayo7451601434771683422.mp3" duration="34000" size="23450"/>
394
+ </complete>
395
+ MESSAGE
396
+ end
397
+
398
+ describe "#reason" do
399
+ subject { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root).reason }
400
+
401
+ it { is_expected.to be_instance_of klass }
402
+
403
+ describe '#name' do
404
+ subject { super().name }
405
+ it { is_expected.to eq(element_name) }
406
+ end
407
+ end
408
+
409
+ describe "#recording" do
410
+ subject { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root).recording }
411
+
412
+ it { is_expected.to be_instance_of Adhearsion::Rayo::Component::Record::Recording }
413
+
414
+ describe '#uri' do
415
+ subject { super().uri }
416
+ it { is_expected.to eq("file:/tmp/rayo7451601434771683422.mp3") }
417
+ end
418
+
419
+ describe '#duration' do
420
+ subject { super().duration }
421
+ it { is_expected.to eq(34000) }
422
+ end
423
+
424
+ describe '#size' do
425
+ subject { super().size }
426
+ it { is_expected.to eq(23450) }
427
+ end
428
+ end
429
+ end
430
+ end
431
+
432
+ describe Adhearsion::Event::Complete::Stop do
433
+ let :stanza do
434
+ <<-MESSAGE
435
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
436
+ <stop xmlns='urn:xmpp:rayo:ext:complete:1' />
437
+ <recording xmlns='urn:xmpp:rayo:record:complete:1' uri="file:/tmp/rayo7451601434771683422.mp3"/>
438
+ </complete>
439
+ MESSAGE
440
+ end
441
+
442
+ describe "#reason" do
443
+ subject { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root).reason }
444
+
445
+ it { is_expected.to be_instance_of Adhearsion::Event::Complete::Stop }
446
+
447
+ describe '#name' do
448
+ subject { super().name }
449
+ it { is_expected.to eq(:stop) }
450
+ end
451
+ end
452
+
453
+ describe "#recording" do
454
+ subject { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root).recording }
455
+
456
+ it { is_expected.to be_instance_of Adhearsion::Rayo::Component::Record::Recording }
457
+
458
+ describe '#uri' do
459
+ subject { super().uri }
460
+ it { is_expected.to eq("file:/tmp/rayo7451601434771683422.mp3") }
461
+ end
462
+ end
463
+ end
464
+
465
+ describe Adhearsion::Event::Complete::Hangup do
466
+ let :stanza do
467
+ <<-MESSAGE
468
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
469
+ <hangup xmlns='urn:xmpp:rayo:ext:complete:1' />
470
+ <recording xmlns='urn:xmpp:rayo:record:complete:1' uri="file:/tmp/rayo7451601434771683422.mp3"/>
471
+ </complete>
472
+ MESSAGE
473
+ end
474
+
475
+ describe "#reason" do
476
+ subject { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root).reason }
477
+
478
+ it { is_expected.to be_instance_of Adhearsion::Event::Complete::Hangup }
479
+
480
+ describe '#name' do
481
+ subject { super().name }
482
+ it { is_expected.to eq(:hangup) }
483
+ end
484
+ end
485
+
486
+ describe "#recording" do
487
+ subject { Adhearsion::Rayo::RayoNode.from_xml(parse_stanza(stanza).root).recording }
488
+
489
+ it { is_expected.to be_instance_of Adhearsion::Rayo::Component::Record::Recording }
490
+
491
+ describe '#uri' do
492
+ subject { super().uri }
493
+ it { is_expected.to eq("file:/tmp/rayo7451601434771683422.mp3") }
494
+ end
495
+ end
496
+ end
497
+ end