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,144 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Adhearsion::Rayo::Component::SendFax do
6
+ it 'registers itself' do
7
+ expect(Adhearsion::Rayo::RayoNode.class_from_registration(:sendfax, 'urn:xmpp:rayo:fax:1')).to eq(described_class)
8
+ end
9
+
10
+ subject do
11
+ described_class.new render_documents: [Adhearsion::Rayo::Component::SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff', pages: [1..4,5,7..9])]
12
+ end
13
+
14
+ describe '#render_documents' do
15
+ subject { super().render_documents }
16
+ it { is_expected.to eq([Adhearsion::Rayo::Component::SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff', pages: [1..4,5,7..9])]) }
17
+ end
18
+
19
+ describe "exporting to Rayo" do
20
+ it "should export to XML that can be understood by its parser" do
21
+ new_instance = Adhearsion::Rayo::RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
22
+ expect(new_instance.render_documents).to eq([Adhearsion::Rayo::Component::SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff', pages: [1..4,5,7..9])])
23
+ end
24
+ end
25
+
26
+ context "without optional attributes" do
27
+ subject do
28
+ described_class.new render_documents: [Adhearsion::Rayo::Component::SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff')]
29
+ end
30
+
31
+ describe "exporting to Rayo" do
32
+ it "should export to XML that can be understood by its parser" do
33
+ new_instance = Adhearsion::Rayo::RayoNode.from_xml Nokogiri::XML(subject.to_rayo.to_xml, nil, nil, Nokogiri::XML::ParseOptions::NOBLANKS).root
34
+ expect(new_instance.render_documents).to eq([Adhearsion::Rayo::Component::SendFax::FaxDocument.new(url: 'http://example.com/faxes/document.tiff')])
35
+ end
36
+ end
37
+ end
38
+
39
+ context "from a rayo stanza" do
40
+ subject { Adhearsion::Rayo::RayoNode.from_xml parse_stanza(stanza).root, '9f00061', '1' }
41
+
42
+ let :stanza do
43
+ <<-MESSAGE
44
+ <sendfax xmlns='urn:xmpp:rayo:fax:1'>
45
+ <document xmlns='urn:xmpp:rayo:fax:1' url='http://shakespere.lit/my_fax.tiff' identity='+14045555555' header='Hello world' pages='1-4,5,7-9'/>
46
+ </sendfax>
47
+ MESSAGE
48
+ end
49
+
50
+ describe '#render_documents' do
51
+ subject { super().render_documents }
52
+ it { is_expected.to eq([Adhearsion::Rayo::Component::SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9])]) }
53
+ end
54
+
55
+ context "without optional attributes" do
56
+ let :stanza do
57
+ <<-MESSAGE
58
+ <sendfax xmlns='urn:xmpp:rayo:fax:1'>
59
+ <document xmlns='urn:xmpp:rayo:fax:1' url='http://shakespere.lit/my_fax.tiff'/>
60
+ </sendfax>
61
+ MESSAGE
62
+ end
63
+
64
+ describe '#render_documents' do
65
+ subject { super().render_documents }
66
+ it { is_expected.to eq([Adhearsion::Rayo::Component::SendFax::FaxDocument.new(url: 'http://shakespere.lit/my_fax.tiff')]) }
67
+ end
68
+ end
69
+ end
70
+ end
71
+
72
+ describe Adhearsion::Rayo::Component::SendFax::FaxDocument do
73
+ it "registers itself" do
74
+ expect(Adhearsion::Rayo::RayoNode.class_from_registration(:document, 'urn:xmpp:rayo:fax:1')).to eq(described_class)
75
+ end
76
+
77
+ subject { described_class.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9]) }
78
+
79
+ describe '#url' do
80
+ subject { super().url }
81
+ it { is_expected.to eq('http://shakespere.lit/my_fax.tiff') }
82
+ end
83
+
84
+ describe '#identity' do
85
+ subject { super().identity }
86
+ it { is_expected.to eq('+14045555555') }
87
+ end
88
+
89
+ describe '#header' do
90
+ subject { super().header }
91
+ it { is_expected.to eq('Hello world') }
92
+ end
93
+
94
+ describe '#pages' do
95
+ subject { super().pages }
96
+ it { is_expected.to eq([1..4,5,7..9]) }
97
+ end
98
+
99
+ context "without optional attributes" do
100
+ subject { described_class.new(url: 'http://shakespere.lit/my_fax.tiff') }
101
+
102
+ describe '#url' do
103
+ subject { super().url }
104
+ it { is_expected.to eq('http://shakespere.lit/my_fax.tiff') }
105
+ end
106
+
107
+ describe '#identity' do
108
+ subject { super().identity }
109
+ it { is_expected.to be_nil }
110
+ end
111
+
112
+ describe '#header' do
113
+ subject { super().header }
114
+ it { is_expected.to be_nil }
115
+ end
116
+
117
+ describe '#pages' do
118
+ subject { super().pages }
119
+ it { is_expected.to be_nil }
120
+ end
121
+ end
122
+
123
+ describe "comparison" do
124
+ it "should be the same with the same attributes" do
125
+ is_expected.to eq(described_class.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9]))
126
+ end
127
+
128
+ it "should be different with a different url" do
129
+ is_expected.not_to eq(described_class.new(url: 'http://shakespere.lit/my_other_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,7..9]))
130
+ end
131
+
132
+ it "should be different with a different identity" do
133
+ is_expected.not_to eq(described_class.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555556', header: 'Hello world', pages: [1..4,5,7..9]))
134
+ end
135
+
136
+ it "should be different with a different header" do
137
+ is_expected.not_to eq(described_class.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello Paul', pages: [1..4,5,7..9]))
138
+ end
139
+
140
+ it "should be different with a different pages" do
141
+ is_expected.not_to eq(described_class.new(url: 'http://shakespere.lit/my_fax.tiff', identity: '+14045555555', header: 'Hello world', pages: [1..4,5,6..9]))
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Adhearsion::Rayo::Connection::Asterisk do
6
+ let :options do
7
+ {
8
+ :host => '127.0.0.1',
9
+ :port => 5038,
10
+ :username => 'test',
11
+ :password => 'test'
12
+ }
13
+ end
14
+
15
+ let(:mock_event_handler) { double('Event Handler').as_null_object }
16
+
17
+ subject(:connection) { described_class.new options }
18
+
19
+ before do
20
+ connection.event_handler = mock_event_handler
21
+ end
22
+
23
+ describe '#ami_client' do
24
+ subject { connection.ami_client }
25
+
26
+ it { is_expected.to be_a described_class::RubyAMIStreamProxy }
27
+ end
28
+
29
+ describe '#ami_client' do
30
+ describe '#stream' do
31
+ subject { connection.ami_client.stream }
32
+
33
+ it { is_expected.to be_a RubyAMI::Stream }
34
+ end
35
+ end
36
+
37
+ it 'should set the connection on the translator' do
38
+ expect(subject.translator.connection).to be subject
39
+ end
40
+
41
+ describe '#run' do
42
+ it 'starts the RubyAMI::Stream' do
43
+ skip "Replace with integration tests"
44
+ expect(subject.ami_client.wrapped_object).to receive(:run).once do
45
+ subject.ami_client.terminate
46
+ end
47
+ expect { subject.run }.to raise_error Adhearsion::Rayo::DisconnectedError
48
+ end
49
+
50
+ it 'rebuilds the RubyAMI::Stream if dead' do
51
+ skip
52
+ expect(subject.ami_client.async).to receive(:run).once do
53
+ subject.ami_client.terminate
54
+ end
55
+ expect { subject.run }.to raise_error DisconnectedError
56
+ expect(subject.ami_client.alive?).to be_falsey
57
+ expect(subject).to receive(:new_ami_stream).once do
58
+ expect(subject.ami_client.alive?).to be true
59
+ expect(subject.ami_client.async).to receive(:run).once
60
+ end
61
+ expect { subject.run }.not_to raise_error
62
+ end
63
+ end
64
+
65
+ describe '#stop' do
66
+ it 'stops the RubyAMI::Stream' do
67
+ expect(subject.ami_client).to receive(:terminate).once
68
+ subject.stop
69
+ end
70
+
71
+ it 'shuts down the translator' do
72
+ expect(subject.translator).to receive(:terminate).once
73
+ subject.stop
74
+ end
75
+ end
76
+
77
+ it 'sends events from RubyAMI to the translator' do
78
+ skip "Replace with integration tests"
79
+ event = RubyAMI::Event.new 'FullyBooted'
80
+ expect(subject.translator.async).to receive(:handle_ami_event).once.with event
81
+ expect(subject.translator.async).to receive(:handle_ami_event).once.with RubyAMI::Stream::Disconnected.new
82
+ subject.ami_client.message_received event
83
+ end
84
+
85
+ describe '#write' do
86
+ it 'sends a command to the translator' do
87
+ skip "Replace with integration tests"
88
+ command = double 'Command'
89
+ options = {:foo => :bar}
90
+ expect(subject.translator.async).to receive(:execute_command).once.with command, options
91
+ subject.write command, options
92
+ end
93
+ end
94
+
95
+ describe 'when a rayo event is received from the translator' do
96
+ it 'should call the event handler with the event' do
97
+ offer = Adhearsion::Event::Offer.new
98
+ offer.target_call_id = '9f00061'
99
+
100
+ expect(mock_event_handler).to receive(:call).once.with offer
101
+ subject.handle_event offer
102
+ end
103
+ end
104
+
105
+ describe '#new_call_uri' do
106
+ it "should return a random UUID" do
107
+ stub_uuids 'foobar'
108
+ expect(subject.new_call_uri).to eq('foobar')
109
+ end
110
+ end
111
+
112
+ describe '#send_message' do
113
+ it 'passes the message to the translator for dispatch' do
114
+ expect(subject.translator).to receive(:send_message).once.with(:foo)
115
+ subject.send_message :foo
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,449 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Adhearsion::Rayo::Connection::XMPP do
6
+ let(:options) { { :root_domain => 'rayo.net' } }
7
+ let(:connection) { described_class.new({:username => '1@app.rayo.net', :password => 1}.merge(options)) }
8
+
9
+ let(:mock_event_handler) { double('Event Handler').as_null_object }
10
+
11
+ before do
12
+ connection.event_handler = mock_event_handler
13
+ end
14
+
15
+ subject { connection }
16
+
17
+ describe "rayo domains" do
18
+ before { stub_uuids 'randomcallid' }
19
+
20
+ context "with no domains specified, and a JID of 1@app.rayo.net" do
21
+ let(:options) { { :username => '1@app.rayo.net' } }
22
+
23
+ describe '#root_domain' do
24
+ subject { super().root_domain }
25
+ it { is_expected.to eq('app.rayo.net') }
26
+ end
27
+
28
+ describe '#new_call_uri' do
29
+ it "should return an appropriate random call URI" do
30
+ expect(subject.new_call_uri).to eq('xmpp:randomcallid@app.rayo.net')
31
+ end
32
+ end
33
+ end
34
+
35
+ context "with only a rayo domain set" do
36
+ let(:options) { { :rayo_domain => 'rayo.org' } }
37
+
38
+ describe '#root_domain' do
39
+ subject { super().root_domain }
40
+ it { is_expected.to eq('rayo.org') }
41
+ end
42
+
43
+ describe '#new_call_uri' do
44
+ it "should return an appropriate random call URI" do
45
+ expect(subject.new_call_uri).to eq('xmpp:randomcallid@rayo.org')
46
+ end
47
+ end
48
+ end
49
+
50
+ context "with only a root domain set" do
51
+ let(:options) { { :root_domain => 'rayo.org' } }
52
+
53
+ describe '#root_domain' do
54
+ subject { super().root_domain }
55
+ it { is_expected.to eq('rayo.org') }
56
+ end
57
+
58
+ describe '#new_call_uri' do
59
+ it "should return an appropriate random call URI" do
60
+ expect(subject.new_call_uri).to eq('xmpp:randomcallid@rayo.org')
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ it 'should require a username and password to be passed in the options' do
67
+ expect { described_class.new :password => 1 }.to raise_error ArgumentError
68
+ expect { described_class.new :username => 1 }.to raise_error ArgumentError
69
+ end
70
+
71
+ it 'should properly set the Blather logger' do
72
+ connection = described_class.new :username => '1@call.rayo.net', :password => 1
73
+ expect(Blather.logger).to be connection.logger
74
+ end
75
+
76
+ it "looking up original command by command ID" do
77
+ skip
78
+ offer = Adhearsion::Event::Offer.new
79
+ offer.call_id = '9f00061'
80
+ offer.to = 'sip:whatever@127.0.0.1'
81
+ output = <<-MSG
82
+ <output xmlns='urn:xmpp:rayo:output:1'>
83
+ <audio url='http://acme.com/greeting.mp3'>
84
+ Thanks for calling ACME company
85
+ </audio>
86
+ <audio url='http://acme.com/package-shipped.mp3'>
87
+ Your package was shipped on
88
+ </audio>
89
+ <say-as interpret-as='date'>12/01/2011</say-as>
90
+ </output>
91
+ MSG
92
+ output = RayoNode.import parse_stanza(output).root
93
+ expect(connection).to receive(:write_to_stream).once.and_return true
94
+ iq = Blather::Stanza::Iq.new :set, '9f00061@call.rayo.net'
95
+ expect(connection).to receive(:create_iq).and_return iq
96
+
97
+ write_thread = Thread.new do
98
+ connection.write offer.call_id, output
99
+ end
100
+
101
+ result = import_stanza <<-MSG
102
+ <iq type='result' from='16577@app.rayo.net/1' to='9f00061@call.rayo.net/1' id='#{iq.id}'>
103
+ <ref id='fgh4590' xmlns='urn:xmpp:rayo:1' />
104
+ </iq>
105
+ MSG
106
+
107
+ 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
108
+
109
+ connection.__send__ :handle_iq_result, result
110
+
111
+ write_thread.join
112
+
113
+ expect(output.state_name).to eq(:executing)
114
+
115
+ expect(connection.original_component_from_id('fgh4590')).to eq(output)
116
+
117
+ example_complete = import_stanza <<-MSG
118
+ <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
119
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
120
+ <success xmlns='urn:xmpp:rayo:output:complete:1' />
121
+ </complete>
122
+ </presence>
123
+ MSG
124
+
125
+ connection.__send__ :handle_presence, example_complete
126
+ expect(output.complete_event(0.5).source).to eq(output)
127
+
128
+ expect(output.component_id).to eq('fgh4590')
129
+ end
130
+
131
+ let(:client) { connection.send :client }
132
+ before { allow(client).to receive :write }
133
+
134
+ describe "sending a command" do
135
+ let(:command) { Adhearsion::Rayo::Command::Answer.new request_id: 'fooobarrr', target_call_id: 'foo', domain: 'bar.com' }
136
+
137
+ it "should write an IQ containing the command to the socket" do
138
+ expect(client).to receive(:write).once.with(satisfy { |stanza|
139
+ expect(stanza).to be_a Blather::Stanza::Iq
140
+ expect(stanza.to).to eq('foo@bar.com')
141
+ expect(stanza.type).to eq(:set)
142
+ })
143
+ connection.write command
144
+ end
145
+
146
+ it "should put the command in a requested state" do
147
+ connection.write command
148
+ expect(command).to be_requested
149
+ end
150
+
151
+ it "should use the command's request_id as the ID id" do
152
+ expect(client).to receive(:write).once.with(satisfy { |stanza|
153
+ expect(stanza.id).to eq('fooobarrr')
154
+ })
155
+ connection.write command
156
+ end
157
+ end
158
+
159
+ it 'should send a "Chat" presence when ready' do
160
+ expect(client).to receive(:write).once.with(satisfy { |stanza|
161
+ expect(stanza.to).to eq('rayo.net')
162
+ expect(stanza).to be_a Blather::Stanza::Presence::Status
163
+ expect(stanza.chat?).to be true
164
+ })
165
+ connection.ready!
166
+ end
167
+
168
+ it 'should send a "Do Not Disturb" presence when not_ready' do
169
+ expect(client).to receive(:write).once.with(satisfy { |stanza|
170
+ expect(stanza.to).to eq('rayo.net')
171
+ expect(stanza).to be_a Blather::Stanza::Presence::Status
172
+ expect(stanza.dnd?).to be true
173
+ })
174
+ connection.not_ready!
175
+ end
176
+
177
+ describe '#send_message' do
178
+ it 'should send a "normal" message to the given user and domain' do
179
+ expect(client).to receive(:write).once.with(satisfy { |stanza|
180
+ expect(stanza.to).to eq('someone@example.org')
181
+ expect(stanza).to be_a Blather::Stanza::Message
182
+ expect(stanza.type).to eq(:normal)
183
+ expect(stanza.body).to eq('Hello World!')
184
+ expect(stanza.subject).to be_nil
185
+ })
186
+ connection.send_message 'someone', 'example.org', 'Hello World!'
187
+ end
188
+
189
+ it 'should default to the root domain' do
190
+ expect(client).to receive(:write).once.with(satisfy { |stanza|
191
+ expect(stanza.to).to eq('someone@rayo.net')
192
+ })
193
+ connection.send_message "someone", nil, nil
194
+ end
195
+
196
+ it 'should send a message with the given subject' do
197
+ expect(client).to receive(:write).once.with(satisfy { |stanza|
198
+ expect(stanza.subject).to eq("Important Message")
199
+ })
200
+ connection.send_message nil, nil, nil, :subject => "Important Message"
201
+ end
202
+ end
203
+
204
+ describe '#handle_presence' do
205
+ let :complete_xml do
206
+ <<-MSG
207
+ <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
208
+ <complete xmlns='urn:xmpp:rayo:ext:1'>
209
+ <success xmlns='urn:xmpp:rayo:output:complete:1' />
210
+ </complete>
211
+ </presence>
212
+ MSG
213
+ end
214
+
215
+ let(:example_complete) { import_stanza complete_xml }
216
+
217
+ it { expect(example_complete).to be_a Blather::Stanza::Presence }
218
+
219
+ describe "accessing the rayo node for a presence stanza" do
220
+ it "should import the rayo node" do
221
+ expect(example_complete.rayo_node).to be_a Adhearsion::Event::Complete
222
+ end
223
+
224
+ it "should be memoized" do
225
+ expect(example_complete.rayo_node).to be example_complete.rayo_node
226
+ end
227
+ end
228
+
229
+ describe "presence received" do
230
+ let(:handle_presence) { connection.__send__ :handle_presence, example_event }
231
+
232
+ describe "from an offer" do
233
+ let :offer_xml do
234
+ <<-MSG
235
+ <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net'>
236
+ <offer xmlns="urn:xmpp:rayo:1" to="sip:whatever@127.0.0.1" from="sip:ylcaomxb@192.168.1.9">
237
+ <header name="Max-Forwards" value="70"/>
238
+ <header name="Content-Length" value="367"/>
239
+ </offer>
240
+ </presence>
241
+ MSG
242
+ end
243
+
244
+ before do
245
+ @now = DateTime.now
246
+ allow(DateTime).to receive_messages now: @now
247
+ end
248
+
249
+ let(:example_event) { import_stanza offer_xml }
250
+
251
+ it { expect(example_event).to be_a Blather::Stanza::Presence }
252
+
253
+ it 'should call the event handler with the event' do
254
+ expect(mock_event_handler).to receive(:call).once.with(satisfy { |event|
255
+ expect(event).to be_instance_of Adhearsion::Event::Offer
256
+ expect(event.target_call_id).to eq('9f00061')
257
+ expect(event.source_uri).to eq('xmpp:9f00061@call.rayo.net')
258
+ expect(event.domain).to eq('call.rayo.net')
259
+ expect(event.transport).to eq('xmpp')
260
+ expect(event.timestamp).to eq(@now)
261
+ })
262
+ handle_presence
263
+ end
264
+
265
+ context "with a delayed delivery timestamp" do
266
+ let :offer_xml do
267
+ <<-MSG
268
+ <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net'>
269
+ <offer xmlns="urn:xmpp:rayo:1" to="sip:whatever@127.0.0.1" from="sip:ylcaomxb@192.168.1.9"/>
270
+ <delay xmlns='urn:xmpp:delay' stamp='2002-09-10T23:08:25Z'/>
271
+ </presence>
272
+ MSG
273
+ end
274
+
275
+ it 'should stamp that time on the rayo event' do
276
+ expect(mock_event_handler).to receive(:call).once.with(satisfy { |event|
277
+ expect(event.timestamp).to eq(DateTime.new(2002, 9, 10, 23, 8, 25, 0))
278
+ })
279
+ handle_presence
280
+ end
281
+ end
282
+ end
283
+
284
+ describe "from something that's not a real event" do
285
+ let :irrelevant_xml do
286
+ <<-MSG
287
+ <presence to='16577@app.rayo.net/1' from='9f00061@call.rayo.net/fgh4590'>
288
+ <foo bar="baz"/>
289
+ </presence>
290
+ MSG
291
+ end
292
+
293
+ let(:example_event) { import_stanza irrelevant_xml }
294
+
295
+ it 'should not be considered to be a rayo event' do
296
+ expect(example_event.rayo_event?).to be_falsey
297
+ end
298
+
299
+ it 'should have a nil rayo_node' do
300
+ expect(example_event.rayo_node).to be_nil
301
+ end
302
+
303
+ it 'should not handle the event' do
304
+ expect(mock_event_handler).to receive(:call).never
305
+ expect { handle_presence }.to throw_symbol(:pass)
306
+ end
307
+ end
308
+ end
309
+ end
310
+
311
+ describe "#handle_error" do
312
+ let(:call_id) { "f6d437f4-1e18-457b-99f8-b5d853f50347" }
313
+ let(:component_id) { 'abc123' }
314
+ let :error_xml do
315
+ <<-MSG
316
+ <iq type="error" id="blather000e" from="f6d437f4-1e18-457b-99f8-b5d853f50347@call.rayo.net/abc123" to="usera@rayo.net">
317
+ <output xmlns="urn:xmpp:rayo:output:1"/>
318
+ <error type="cancel">
319
+ <item-not-found xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/>
320
+ <text xmlns="urn:ietf:params:xml:ns:xmpp-stanzas" lang="en">Could not find call [id=f6d437f4-1e18-457b-99f8-b5d853f50347]</text>
321
+ </error>
322
+ </iq>
323
+ MSG
324
+ end
325
+
326
+ let(:example_error) { import_stanza error_xml }
327
+ let(:cmd) { Adhearsion::Rayo::Component::Output.new }
328
+
329
+ before do
330
+ cmd.request!
331
+ connection.__send__ :handle_error, example_error, cmd
332
+ end
333
+
334
+ subject { cmd.response }
335
+
336
+ it "should have the correct call ID" do
337
+ expect(subject.call_id).to eq(call_id)
338
+ end
339
+
340
+ it "should have the correct component ID" do
341
+ expect(subject.component_id).to eq(component_id)
342
+ end
343
+
344
+ it "should have the correct name" do
345
+ expect(subject.name).to eq(:item_not_found)
346
+ end
347
+
348
+ it "should have the correct text" do
349
+ expect(subject.text).to eq('Could not find call [id=f6d437f4-1e18-457b-99f8-b5d853f50347]')
350
+ end
351
+ end
352
+
353
+ describe "#prep_command_for_execution" do
354
+ let(:stanza) { subject.prep_command_for_execution command }
355
+
356
+ context "with a dial command" do
357
+ let(:command) { Adhearsion::Rayo::Command::Dial.new }
358
+ let(:expected_jid) { 'rayo.net' }
359
+
360
+ it "should use the correct JID" do
361
+ stanza = subject.prep_command_for_execution command
362
+ expect(stanza.to).to eq(expected_jid)
363
+ end
364
+ end
365
+
366
+ context "with a call command" do
367
+ let(:command) { Adhearsion::Rayo::Command::Answer.new target_call_id: 'abc123' }
368
+ let(:expected_jid) { 'abc123@rayo.net' }
369
+
370
+ it "should use the correct JID" do
371
+ expect(stanza.to).to eq(expected_jid)
372
+ end
373
+
374
+ context "with a domain specified" do
375
+ let(:expected_jid) { 'abc123@calls.rayo.net' }
376
+
377
+ it "should use the specified domain in the JID" do
378
+ stanza = subject.prep_command_for_execution command, domain: 'calls.rayo.net'
379
+ expect(stanza.to).to eq(expected_jid)
380
+ end
381
+ end
382
+ end
383
+
384
+ context "with a call component" do
385
+ let(:command) { Adhearsion::Rayo::Component::Output.new :target_call_id => 'abc123' }
386
+ let(:expected_jid) { 'abc123@rayo.net' }
387
+
388
+ it "should use the correct JID" do
389
+ expect(stanza.to).to eq(expected_jid)
390
+ end
391
+ end
392
+
393
+ context "with a call component command" do
394
+ let(:command) { Adhearsion::Rayo::Component::Stop.new :target_call_id => 'abc123', :component_id => 'foobar' }
395
+ let(:expected_jid) { 'abc123@rayo.net/foobar' }
396
+
397
+ it "should use the correct JID" do
398
+ expect(stanza.to).to eq(expected_jid)
399
+ end
400
+ end
401
+
402
+ context "with a mixer component" do
403
+ let(:command) { Adhearsion::Rayo::Component::Output.new :target_mixer_name => 'abc123' }
404
+ let(:expected_jid) { 'abc123@rayo.net' }
405
+
406
+ it "should use the correct JID" do
407
+ expect(stanza.to).to eq(expected_jid)
408
+ end
409
+ end
410
+
411
+ context "with a mixer component command" do
412
+ let(:command) { Adhearsion::Rayo::Component::Stop.new :target_mixer_name => 'abc123', :component_id => 'foobar' }
413
+ let(:expected_jid) { 'abc123@rayo.net/foobar' }
414
+
415
+ it "should use the correct JID" do
416
+ expect(stanza.to).to eq(expected_jid)
417
+ end
418
+ end
419
+ end
420
+
421
+ describe "receiving events from a mixer" do
422
+ context "after joining the mixer" do
423
+ before do
424
+ expect(client).to receive :write_with_handler
425
+ subject.write Adhearsion::Rayo::Command::Join.new(:mixer_name => 'foomixer')
426
+ end
427
+
428
+ let :active_speaker_xml do
429
+ <<-MSG
430
+ <presence to='16577@app.rayo.net/1' from='foomixer@rayo.net'>
431
+ <started-speaking xmlns="urn:xmpp:rayo:1" call-id="foocall"/>
432
+ </presence>
433
+ MSG
434
+ end
435
+
436
+ let(:active_speaker_event) { import_stanza active_speaker_xml }
437
+
438
+ it "should tag those events with a mixer name, rather than a call ID" do
439
+ expect(mock_event_handler).to receive(:call).once.with(satisfy { |event|
440
+ expect(event).to be_instance_of Adhearsion::Event::StartedSpeaking
441
+ expect(event.target_mixer_name).to eq('foomixer')
442
+ expect(event.target_call_id).to be nil
443
+ expect(event.domain).to eq('rayo.net')
444
+ })
445
+ connection.__send__ :handle_presence, active_speaker_event
446
+ end
447
+ end
448
+ end
449
+ end