lygneo-vines 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (174) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile +3 -0
  3. data/LICENSE +19 -0
  4. data/README.md +7 -0
  5. data/Rakefile +23 -0
  6. data/bin/vines +4 -0
  7. data/conf/certs/README +39 -0
  8. data/conf/certs/ca-bundle.crt +3895 -0
  9. data/conf/config.rb +42 -0
  10. data/lib/vines/cli.rb +132 -0
  11. data/lib/vines/cluster/connection.rb +26 -0
  12. data/lib/vines/cluster/publisher.rb +55 -0
  13. data/lib/vines/cluster/pubsub.rb +92 -0
  14. data/lib/vines/cluster/sessions.rb +125 -0
  15. data/lib/vines/cluster/subscriber.rb +108 -0
  16. data/lib/vines/cluster.rb +246 -0
  17. data/lib/vines/command/bcrypt.rb +12 -0
  18. data/lib/vines/command/cert.rb +50 -0
  19. data/lib/vines/command/init.rb +68 -0
  20. data/lib/vines/command/ldap.rb +38 -0
  21. data/lib/vines/command/restart.rb +12 -0
  22. data/lib/vines/command/schema.rb +24 -0
  23. data/lib/vines/command/start.rb +28 -0
  24. data/lib/vines/command/stop.rb +18 -0
  25. data/lib/vines/config/host.rb +125 -0
  26. data/lib/vines/config/port.rb +132 -0
  27. data/lib/vines/config/pubsub.rb +108 -0
  28. data/lib/vines/config.rb +223 -0
  29. data/lib/vines/daemon.rb +78 -0
  30. data/lib/vines/error.rb +150 -0
  31. data/lib/vines/follower.rb +111 -0
  32. data/lib/vines/jid.rb +95 -0
  33. data/lib/vines/kit.rb +23 -0
  34. data/lib/vines/log.rb +24 -0
  35. data/lib/vines/router.rb +179 -0
  36. data/lib/vines/stanza/iq/auth.rb +18 -0
  37. data/lib/vines/stanza/iq/disco_info.rb +45 -0
  38. data/lib/vines/stanza/iq/disco_items.rb +29 -0
  39. data/lib/vines/stanza/iq/error.rb +16 -0
  40. data/lib/vines/stanza/iq/ping.rb +16 -0
  41. data/lib/vines/stanza/iq/private_storage.rb +83 -0
  42. data/lib/vines/stanza/iq/query.rb +10 -0
  43. data/lib/vines/stanza/iq/result.rb +16 -0
  44. data/lib/vines/stanza/iq/roster.rb +140 -0
  45. data/lib/vines/stanza/iq/session.rb +17 -0
  46. data/lib/vines/stanza/iq/vcard.rb +56 -0
  47. data/lib/vines/stanza/iq/version.rb +25 -0
  48. data/lib/vines/stanza/iq.rb +48 -0
  49. data/lib/vines/stanza/message.rb +40 -0
  50. data/lib/vines/stanza/presence/error.rb +23 -0
  51. data/lib/vines/stanza/presence/probe.rb +37 -0
  52. data/lib/vines/stanza/presence/subscribe.rb +42 -0
  53. data/lib/vines/stanza/presence/subscribed.rb +51 -0
  54. data/lib/vines/stanza/presence/unavailable.rb +15 -0
  55. data/lib/vines/stanza/presence/unsubscribe.rb +38 -0
  56. data/lib/vines/stanza/presence/unsubscribed.rb +38 -0
  57. data/lib/vines/stanza/presence.rb +141 -0
  58. data/lib/vines/stanza/pubsub/create.rb +39 -0
  59. data/lib/vines/stanza/pubsub/delete.rb +41 -0
  60. data/lib/vines/stanza/pubsub/publish.rb +66 -0
  61. data/lib/vines/stanza/pubsub/subscribe.rb +44 -0
  62. data/lib/vines/stanza/pubsub/unsubscribe.rb +30 -0
  63. data/lib/vines/stanza/pubsub.rb +22 -0
  64. data/lib/vines/stanza.rb +175 -0
  65. data/lib/vines/storage/ldap.rb +71 -0
  66. data/lib/vines/storage/local.rb +139 -0
  67. data/lib/vines/storage/null.rb +39 -0
  68. data/lib/vines/storage/sql.rb +138 -0
  69. data/lib/vines/storage.rb +239 -0
  70. data/lib/vines/store.rb +110 -0
  71. data/lib/vines/stream/client/auth.rb +74 -0
  72. data/lib/vines/stream/client/auth_restart.rb +29 -0
  73. data/lib/vines/stream/client/bind.rb +72 -0
  74. data/lib/vines/stream/client/bind_restart.rb +24 -0
  75. data/lib/vines/stream/client/closed.rb +13 -0
  76. data/lib/vines/stream/client/ready.rb +17 -0
  77. data/lib/vines/stream/client/session.rb +210 -0
  78. data/lib/vines/stream/client/start.rb +27 -0
  79. data/lib/vines/stream/client/tls.rb +38 -0
  80. data/lib/vines/stream/client.rb +84 -0
  81. data/lib/vines/stream/component/handshake.rb +26 -0
  82. data/lib/vines/stream/component/ready.rb +23 -0
  83. data/lib/vines/stream/component/start.rb +19 -0
  84. data/lib/vines/stream/component.rb +58 -0
  85. data/lib/vines/stream/http/auth.rb +22 -0
  86. data/lib/vines/stream/http/bind.rb +32 -0
  87. data/lib/vines/stream/http/bind_restart.rb +37 -0
  88. data/lib/vines/stream/http/ready.rb +29 -0
  89. data/lib/vines/stream/http/request.rb +172 -0
  90. data/lib/vines/stream/http/session.rb +120 -0
  91. data/lib/vines/stream/http/sessions.rb +65 -0
  92. data/lib/vines/stream/http/start.rb +23 -0
  93. data/lib/vines/stream/http.rb +157 -0
  94. data/lib/vines/stream/parser.rb +79 -0
  95. data/lib/vines/stream/sasl.rb +128 -0
  96. data/lib/vines/stream/server/auth.rb +13 -0
  97. data/lib/vines/stream/server/auth_restart.rb +13 -0
  98. data/lib/vines/stream/server/final_restart.rb +21 -0
  99. data/lib/vines/stream/server/outbound/auth.rb +31 -0
  100. data/lib/vines/stream/server/outbound/auth_restart.rb +20 -0
  101. data/lib/vines/stream/server/outbound/auth_result.rb +32 -0
  102. data/lib/vines/stream/server/outbound/final_features.rb +28 -0
  103. data/lib/vines/stream/server/outbound/final_restart.rb +20 -0
  104. data/lib/vines/stream/server/outbound/start.rb +20 -0
  105. data/lib/vines/stream/server/outbound/tls.rb +30 -0
  106. data/lib/vines/stream/server/outbound/tls_result.rb +34 -0
  107. data/lib/vines/stream/server/ready.rb +24 -0
  108. data/lib/vines/stream/server/start.rb +13 -0
  109. data/lib/vines/stream/server/tls.rb +13 -0
  110. data/lib/vines/stream/server.rb +150 -0
  111. data/lib/vines/stream/state.rb +60 -0
  112. data/lib/vines/stream.rb +247 -0
  113. data/lib/vines/token_bucket.rb +55 -0
  114. data/lib/vines/user.rb +123 -0
  115. data/lib/vines/version.rb +6 -0
  116. data/lib/vines/xmpp_server.rb +25 -0
  117. data/lib/vines.rb +203 -0
  118. data/test/cluster/publisher_test.rb +57 -0
  119. data/test/cluster/sessions_test.rb +47 -0
  120. data/test/cluster/subscriber_test.rb +109 -0
  121. data/test/config/host_test.rb +369 -0
  122. data/test/config/pubsub_test.rb +187 -0
  123. data/test/config_test.rb +732 -0
  124. data/test/error_test.rb +58 -0
  125. data/test/ext/nokogiri.rb +14 -0
  126. data/test/follower_test.rb +102 -0
  127. data/test/jid_test.rb +147 -0
  128. data/test/kit_test.rb +31 -0
  129. data/test/router_test.rb +243 -0
  130. data/test/stanza/iq/disco_info_test.rb +78 -0
  131. data/test/stanza/iq/disco_items_test.rb +49 -0
  132. data/test/stanza/iq/private_storage_test.rb +184 -0
  133. data/test/stanza/iq/roster_test.rb +229 -0
  134. data/test/stanza/iq/session_test.rb +25 -0
  135. data/test/stanza/iq/vcard_test.rb +146 -0
  136. data/test/stanza/iq/version_test.rb +64 -0
  137. data/test/stanza/iq_test.rb +70 -0
  138. data/test/stanza/message_test.rb +126 -0
  139. data/test/stanza/presence/probe_test.rb +50 -0
  140. data/test/stanza/presence/subscribe_test.rb +83 -0
  141. data/test/stanza/pubsub/create_test.rb +116 -0
  142. data/test/stanza/pubsub/delete_test.rb +169 -0
  143. data/test/stanza/pubsub/publish_test.rb +309 -0
  144. data/test/stanza/pubsub/subscribe_test.rb +205 -0
  145. data/test/stanza/pubsub/unsubscribe_test.rb +148 -0
  146. data/test/stanza_test.rb +85 -0
  147. data/test/storage/ldap_test.rb +201 -0
  148. data/test/storage/local_test.rb +59 -0
  149. data/test/storage/mock_redis.rb +97 -0
  150. data/test/storage/null_test.rb +29 -0
  151. data/test/storage/storage_tests.rb +182 -0
  152. data/test/storage_test.rb +85 -0
  153. data/test/store_test.rb +130 -0
  154. data/test/stream/client/auth_test.rb +137 -0
  155. data/test/stream/client/ready_test.rb +47 -0
  156. data/test/stream/client/session_test.rb +27 -0
  157. data/test/stream/component/handshake_test.rb +52 -0
  158. data/test/stream/component/ready_test.rb +103 -0
  159. data/test/stream/component/start_test.rb +39 -0
  160. data/test/stream/http/auth_test.rb +70 -0
  161. data/test/stream/http/ready_test.rb +86 -0
  162. data/test/stream/http/request_test.rb +209 -0
  163. data/test/stream/http/sessions_test.rb +49 -0
  164. data/test/stream/http/start_test.rb +50 -0
  165. data/test/stream/parser_test.rb +122 -0
  166. data/test/stream/sasl_test.rb +195 -0
  167. data/test/stream/server/auth_test.rb +61 -0
  168. data/test/stream/server/outbound/auth_test.rb +75 -0
  169. data/test/stream/server/ready_test.rb +98 -0
  170. data/test/test_helper.rb +42 -0
  171. data/test/token_bucket_test.rb +44 -0
  172. data/test/user_test.rb +96 -0
  173. data/vines.gemspec +30 -0
  174. metadata +387 -0
@@ -0,0 +1,70 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq do
6
+ subject { Vines::Stanza::Iq.new(xml, stream) }
7
+ let(:stream) { MiniTest::Mock.new }
8
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
9
+ let(:hatter) { Vines::User.new(jid: 'hatter@wonderland.lit/crumpets') }
10
+ let(:config) do
11
+ Vines::Config.new do
12
+ host 'wonderland.lit' do
13
+ storage(:fs) { dir Dir.tmpdir }
14
+ end
15
+ end
16
+ end
17
+
18
+ before do
19
+ class << stream
20
+ attr_accessor :config, :user
21
+ end
22
+ stream.user = hatter
23
+ stream.config = config
24
+ end
25
+
26
+ describe 'when addressed to a user rather than the server itself' do
27
+ let(:recipient) { MiniTest::Mock.new }
28
+ let(:xml) do
29
+ node(%q{
30
+ <iq id="42" type="set" to="alice@wonderland.lit/tea" from="hatter@wonderland.lit/crumpets">
31
+ <si xmlns="http://jabber.org/protocol/si" id="42_si" profile="http://jabber.org/protocol/si/profile/file-transfer">
32
+ <file xmlns="http://jabber.org/protocol/si/profile/file-transfer" name="file" size="1"/>
33
+ <feature xmlns="http://jabber.org/protocol/feature-neg">
34
+ <x xmlns="jabber:x:data" type="form">
35
+ <field var="stream-method" type="list-single">
36
+ <option>
37
+ <value>http://jabber.org/protocol/bytestreams</value>
38
+ </option>
39
+ <option>
40
+ <value>http://jabber.org/protocol/ibb</value>
41
+ </option>
42
+ </field>
43
+ </x>
44
+ </feature>
45
+ </si>
46
+ </iq>
47
+ })
48
+ end
49
+
50
+ before do
51
+ recipient.expect :user, alice, []
52
+ recipient.expect :write, nil, [xml]
53
+ stream.expect :connected_resources, [recipient], [alice.jid]
54
+ end
55
+
56
+ it 'routes the stanza to the users connected resources' do
57
+ subject.process
58
+ stream.verify
59
+ recipient.verify
60
+ end
61
+ end
62
+
63
+ describe 'when given no type or body elements' do
64
+ let(:xml) { node('<iq type="set" id="42"/>') }
65
+
66
+ it 'raises a feature-not-implemented stanza error' do
67
+ -> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,126 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Message do
6
+ subject { Vines::Stanza::Message.new(xml, stream) }
7
+ let(:stream) { MiniTest::Mock.new }
8
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
9
+ let(:romeo) { Vines::User.new(jid: 'romeo@verona.lit/balcony') }
10
+ let(:config) do
11
+ Vines::Config.new do
12
+ host 'wonderland.lit' do
13
+ storage(:fs) { dir Dir.tmpdir }
14
+ end
15
+ end
16
+ end
17
+
18
+ before do
19
+ class << stream
20
+ attr_accessor :config, :user
21
+ end
22
+ stream.user = alice
23
+ stream.config = config
24
+ end
25
+
26
+ describe 'when message type attribute is invalid' do
27
+ let(:xml) { node('<message type="bogus">hello!</message>') }
28
+
29
+ it 'raises a bad-request stanza error' do
30
+ -> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
31
+ end
32
+ end
33
+
34
+ describe 'when the to address is missing' do
35
+ let(:xml) { node('<message>hello!</message>') }
36
+ let(:recipient) { MiniTest::Mock.new }
37
+
38
+ before do
39
+ recipient.expect :user, alice
40
+ recipient.expect :write, nil, [xml]
41
+ stream.expect :connected_resources, [recipient], [alice.jid.bare]
42
+ end
43
+
44
+ it 'sends the message to the senders connected streams' do
45
+ subject.process
46
+ stream.verify
47
+ recipient.verify
48
+ end
49
+ end
50
+
51
+ describe 'when addressed to a non-user' do
52
+ let(:bogus) { Vines::JID.new('bogus@wonderland.lit/cake') }
53
+ let(:xml) { node(%Q{<message to="#{bogus}">hello!</message>}) }
54
+ let(:storage) { MiniTest::Mock.new }
55
+
56
+ before do
57
+ storage.expect :find_user, nil, [bogus]
58
+ stream.expect :storage, storage, [bogus.domain]
59
+ stream.expect :connected_resources, [], [bogus]
60
+ end
61
+
62
+ it 'ignores the stanza' do
63
+ subject.process
64
+ stream.verify
65
+ storage.verify
66
+ end
67
+ end
68
+
69
+ describe 'when addressed to an offline user' do
70
+ let(:hatter) { Vines::User.new(jid: 'hatter@wonderland.lit/cake') }
71
+ let(:xml) { node(%Q{<message to="#{hatter.jid}">hello!</message>}) }
72
+ let(:storage) { MiniTest::Mock.new }
73
+
74
+ before do
75
+ storage.expect :find_user, hatter, [hatter.jid]
76
+ stream.expect :storage, storage, [hatter.jid.domain]
77
+ stream.expect :connected_resources, [], [hatter.jid]
78
+ end
79
+
80
+ it 'raises a service-unavailable stanza error' do
81
+ -> { subject.process }.must_raise Vines::StanzaErrors::ServiceUnavailable
82
+ stream.verify
83
+ storage.verify
84
+ end
85
+ end
86
+
87
+ describe 'when address to a local user in a different domain' do
88
+ let(:xml) { node(%Q{<message to="#{romeo.jid}">hello!</message>}) }
89
+ let(:expected) { node(%Q{<message to="#{romeo.jid}" from="#{alice.jid}">hello!</message>}) }
90
+ let(:recipient) { MiniTest::Mock.new }
91
+
92
+ before do
93
+ recipient.expect :user, romeo
94
+ recipient.expect :write, nil, [expected]
95
+
96
+ config.host 'verona.lit' do
97
+ storage(:fs) { dir Dir.tmpdir }
98
+ end
99
+
100
+ stream.expect :connected_resources, [recipient], [romeo.jid]
101
+ end
102
+
103
+ it 'delivers the stanza to the user' do
104
+ subject.process
105
+ stream.verify
106
+ recipient.verify
107
+ end
108
+ end
109
+
110
+ describe 'when addressed to a remote user' do
111
+ let(:xml) { node(%Q{<message to="#{romeo.jid}">hello!</message>}) }
112
+ let(:expected) { node(%Q{<message to="#{romeo.jid}" from="#{alice.jid}">hello!</message>}) }
113
+ let(:router) { MiniTest::Mock.new }
114
+
115
+ before do
116
+ router.expect :route, nil, [expected]
117
+ stream.expect :router, router
118
+ end
119
+
120
+ it 'routes rather than handle locally' do
121
+ subject.process
122
+ stream.verify
123
+ router.verify
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Presence::Probe do
6
+ def setup
7
+ @alice = Vines::JID.new('alice@wonderland.lit/tea')
8
+ @stream = MiniTest::Mock.new
9
+ @config = Vines::Config.new do
10
+ host 'wonderland.lit' do
11
+ storage(:fs) { dir Dir.tmpdir }
12
+ end
13
+ end
14
+ end
15
+
16
+ def test_missing_to_address_raises
17
+ node = node(%q{<presence id="42" type="probe"/>})
18
+ stanza = Vines::Stanza::Presence::Probe.new(node, @stream)
19
+ def stanza.inbound?; false; end
20
+
21
+ @stream.expect(:user, Vines::User.new(jid: @alice))
22
+
23
+ assert_raises(Vines::StanzaErrors::BadRequest) { stanza.process }
24
+ assert @stream.verify
25
+ end
26
+
27
+ def test_to_remote_address_routes
28
+ node = node(%q{<presence id="42" to="romeo@verona.lit" type="probe"/>})
29
+ stanza = Vines::Stanza::Presence::Probe.new(node, @stream)
30
+ def stanza.inbound?; false; end
31
+
32
+ expected = node(%Q{<presence id="42" to="romeo@verona.lit" type="probe" from="#{@alice}"/>})
33
+ router = MiniTest::Mock.new
34
+ router.expect(:route, nil, [expected])
35
+
36
+ @stream.expect(:router, router)
37
+ @stream.expect(:user, Vines::User.new(jid: @alice))
38
+ @stream.expect(:config, @config)
39
+
40
+ stanza.process
41
+ assert @stream.verify
42
+ assert router.verify
43
+ end
44
+
45
+ private
46
+
47
+ def node(xml)
48
+ Nokogiri::XML(xml).root
49
+ end
50
+ end
@@ -0,0 +1,83 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Presence::Subscribe do
6
+ subject { Vines::Stanza::Presence::Subscribe.new(xml, stream) }
7
+ let(:stream) { MiniTest::Mock.new }
8
+ let(:alice) { Vines::JID.new('alice@wonderland.lit/tea') }
9
+ let(:hatter) { Vines::JID.new('hatter@wonderland.lit') }
10
+ let(:follower) { Vines::Follower.new(jid: hatter) }
11
+
12
+ before do
13
+ class << stream
14
+ attr_accessor :user, :nodes
15
+ def write(node)
16
+ @nodes ||= []
17
+ @nodes << node
18
+ end
19
+ end
20
+ end
21
+
22
+ describe 'outbound subscription to a local jid, but missing follower' do
23
+ let(:xml) { node(%q{<presence id="42" to="hatter@wonderland.lit" type="subscribe"/>}) }
24
+ let(:user) { MiniTest::Mock.new }
25
+ let(:storage) { MiniTest::Mock.new }
26
+ let(:recipient) { MiniTest::Mock.new }
27
+
28
+ before do
29
+ class << user
30
+ attr_accessor :jid
31
+ end
32
+ user.jid = alice
33
+ user.expect :request_subscription, nil, [hatter]
34
+ user.expect :follower, follower, [hatter]
35
+
36
+ storage.expect :save_user, nil, [user]
37
+ storage.expect :find_user, nil, [hatter]
38
+
39
+ recipient.expect :user, user
40
+ class << recipient
41
+ attr_accessor :nodes
42
+ def write(node)
43
+ @nodes ||= []
44
+ @nodes << node
45
+ end
46
+ end
47
+
48
+ stream.user = user
49
+ stream.expect :domain, 'wonderland.lit'
50
+ stream.expect :storage, storage, ['wonderland.lit']
51
+ stream.expect :storage, storage, ['wonderland.lit']
52
+ stream.expect :interested_resources, [recipient], [alice]
53
+ stream.expect :update_user_streams, nil, [user]
54
+
55
+ class << subject
56
+ def route_iq; false; end
57
+ def inbound?; false; end
58
+ def local?; true; end
59
+ end
60
+ end
61
+
62
+ it 'rejects the subscription with an unsubscribed response' do
63
+ subject.process
64
+ stream.verify
65
+ user.verify
66
+ storage.verify
67
+ stream.nodes.size.must_equal 1
68
+
69
+ expected = node(%q{<presence from="hatter@wonderland.lit" id="42" to="alice@wonderland.lit" type="unsubscribed"/>})
70
+ stream.nodes.first.must_equal expected
71
+ end
72
+
73
+ it 'sends a roster set to the interested resources with subscription none' do
74
+ subject.process
75
+ recipient.nodes.size.must_equal 1
76
+
77
+ query = %q{<query xmlns="jabber:iq:roster"><item jid="hatter@wonderland.lit" subscription="none"/></query>}
78
+ expected = node(%Q{<iq to="alice@wonderland.lit/tea" type="set">#{query}</iq>})
79
+ recipient.nodes.first.remove_attribute('id') # id is random
80
+ recipient.nodes.first.must_equal expected
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::PubSub::Create do
6
+ subject { Vines::Stanza::PubSub::Create.new(xml, stream) }
7
+ let(:user) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
8
+ let(:stream) { MiniTest::Mock.new }
9
+ let(:config) do
10
+ Vines::Config.new do
11
+ host 'wonderland.lit' do
12
+ storage(:fs) { dir Dir.tmpdir }
13
+ pubsub 'games'
14
+ end
15
+ end
16
+ end
17
+
18
+ before do
19
+ class << stream
20
+ attr_accessor :config, :nodes, :user
21
+ def write(node)
22
+ @nodes ||= []
23
+ @nodes << node
24
+ end
25
+ end
26
+ stream.config = config
27
+ stream.user = user
28
+ end
29
+
30
+ describe 'when missing a to address' do
31
+ let(:xml) { create('') }
32
+
33
+ it 'raises a feature-not-implemented stanza error' do
34
+ stream.expect :domain, 'wonderland.lit'
35
+ -> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
36
+ stream.verify
37
+ end
38
+ end
39
+
40
+ describe 'when addressed to bare server domain' do
41
+ let(:xml) { create('wonderland.lit') }
42
+
43
+ it 'raises a feature-not-implemented stanza error' do
44
+ -> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
45
+ stream.verify
46
+ end
47
+ end
48
+
49
+ describe 'when addressed to a non-pubsub component' do
50
+ let(:router) { MiniTest::Mock.new }
51
+ let(:xml) { create('bogus.wonderland.lit') }
52
+
53
+ before do
54
+ router.expect :route, nil, [xml]
55
+ stream.expect :router, router
56
+ end
57
+
58
+ it 'routes rather than handle locally' do
59
+ subject.process
60
+ stream.verify
61
+ router.verify
62
+ end
63
+ end
64
+
65
+ describe 'when attempting to create multiple nodes' do
66
+ let(:xml) { create('games.wonderland.lit', true) }
67
+
68
+ it 'raises a bad-request stanza error' do
69
+ -> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
70
+ stream.verify
71
+ end
72
+ end
73
+
74
+ describe 'when attempting to create duplicate nodes' do
75
+ let(:pubsub) { MiniTest::Mock.new }
76
+ let(:xml) { create('games.wonderland.lit') }
77
+
78
+ it 'raises a conflict stanza error' do
79
+ pubsub.expect :node?, true, ['game_13']
80
+ subject.stub :pubsub, pubsub do
81
+ -> { subject.process }.must_raise Vines::StanzaErrors::Conflict
82
+ end
83
+ stream.verify
84
+ pubsub.verify
85
+ end
86
+ end
87
+
88
+ describe 'when given a valid stanza' do
89
+ let(:xml) { create('games.wonderland.lit') }
90
+ let(:expected) { result(user.jid, 'games.wonderland.lit') }
91
+
92
+ it 'sends an iq result stanza to sender' do
93
+ subject.process
94
+ stream.nodes.size.must_equal 1
95
+ stream.nodes.first.must_equal expected
96
+ stream.verify
97
+ end
98
+ end
99
+
100
+ private
101
+
102
+ def create(to, multiple=false)
103
+ extra_create = "<create node='game_14'/>" if multiple
104
+ body = %Q{
105
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
106
+ <create node='game_13'/>
107
+ #{extra_create}
108
+ </pubsub>}
109
+ iq(type: 'set', to: to, id: 42, body: body)
110
+ end
111
+
112
+ def result(to, from)
113
+ body = '<pubsub xmlns="http://jabber.org/protocol/pubsub"><create node="game_13"/></pubsub>'
114
+ iq(from: from, id: 42, to: to, type: 'result', body: body)
115
+ end
116
+ end
@@ -0,0 +1,169 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::PubSub::Delete do
6
+ subject { Vines::Stanza::PubSub::Delete.new(xml, stream) }
7
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
8
+ let(:stream) { MiniTest::Mock.new }
9
+ let(:config) do
10
+ Vines::Config.new do
11
+ host 'wonderland.lit' do
12
+ storage(:fs) { dir Dir.tmpdir }
13
+ pubsub 'games'
14
+ end
15
+ end
16
+ end
17
+
18
+ before do
19
+ class << stream
20
+ attr_accessor :config, :domain, :nodes, :user
21
+ def write(node)
22
+ @nodes ||= []
23
+ @nodes << node
24
+ end
25
+ end
26
+ stream.config = config
27
+ stream.domain = 'wonderland.lit'
28
+ stream.user = alice
29
+ end
30
+
31
+ describe 'when missing a to address' do
32
+ let(:xml) do
33
+ node(%q{
34
+ <iq type='set' id='42'>
35
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
36
+ <delete node='game_13'/>
37
+ </pubsub>
38
+ </iq>
39
+ })
40
+ end
41
+
42
+ it 'raises a feature-not-implemented stanza error' do
43
+ -> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
44
+ stream.verify
45
+ end
46
+ end
47
+
48
+ describe 'when addressed to a bare server domain jid' do
49
+ let(:xml) do
50
+ node(%q{
51
+ <iq type='set' to='wonderland.lit' id='42'>
52
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
53
+ <delete node='game_13'/>
54
+ </pubsub>
55
+ </iq>
56
+ })
57
+ end
58
+
59
+ it 'raises a feature-not-implemented stanza error' do
60
+ -> { subject.process }.must_raise Vines::StanzaErrors::FeatureNotImplemented
61
+ stream.verify
62
+ end
63
+ end
64
+
65
+ describe 'when addressed to a non-pubsub address' do
66
+ let(:router) { MiniTest::Mock.new }
67
+ let(:xml) do
68
+ node(%q{
69
+ <iq type='set' to='bogus.wonderland.lit' id='42'>
70
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
71
+ <delete node='game_13'/>
72
+ </pubsub>
73
+ </iq>
74
+ })
75
+ end
76
+
77
+ before do
78
+ router.expect :route, nil, [xml]
79
+ stream.expect :router, router
80
+ end
81
+
82
+ it 'routes rather than handle locally' do
83
+ subject.process
84
+ stream.verify
85
+ router.verify
86
+ end
87
+ end
88
+
89
+ describe 'when stanza contains multiple delete elements' do
90
+ let(:xml) do
91
+ node(%q{
92
+ <iq type='set' to='games.wonderland.lit' id='42'>
93
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
94
+ <delete node='game_13'/>
95
+ <delete node='game_14'/>
96
+ </pubsub>
97
+ </iq>
98
+ })
99
+ end
100
+
101
+ it 'raises a bad-request stanza error' do
102
+ -> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
103
+ stream.verify
104
+ end
105
+ end
106
+
107
+ describe 'when deleting a missing node' do
108
+ let(:xml) do
109
+ node(%q{
110
+ <iq type='set' to='games.wonderland.lit' id='42'>
111
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
112
+ <delete node='game_13'/>
113
+ </pubsub>
114
+ </iq>
115
+ })
116
+ end
117
+
118
+ it 'raises an item-not-found stanza error' do
119
+ -> { subject.process }.must_raise Vines::StanzaErrors::ItemNotFound
120
+ stream.verify
121
+ end
122
+ end
123
+
124
+ describe 'when valid stanza is received' do
125
+ let(:pubsub) { MiniTest::Mock.new }
126
+ let(:xml) do
127
+ node(%q{
128
+ <iq type='set' to='games.wonderland.lit' id='42'>
129
+ <pubsub xmlns='http://jabber.org/protocol/pubsub'>
130
+ <delete node='game_13'/>
131
+ </pubsub>
132
+ </iq>
133
+ })
134
+ end
135
+
136
+ let(:result) { node(%Q{<iq from="games.wonderland.lit" id="42" to="#{alice.jid}" type="result"/>}) }
137
+
138
+ let(:broadcast) do
139
+ node(%q{
140
+ <message>
141
+ <event xmlns="http://jabber.org/protocol/pubsub#event">
142
+ <delete node="game_13"/>
143
+ </event>
144
+ </message>})
145
+ end
146
+
147
+ before do
148
+ pubsub.expect :node?, true, ['game_13']
149
+ pubsub.expect :publish, nil, ['game_13', broadcast]
150
+ pubsub.expect :delete_node, nil, ['game_13']
151
+ end
152
+
153
+ it 'broadcasts the delete to subscribers' do
154
+ subject.stub :pubsub, pubsub do
155
+ subject.process
156
+ end
157
+ stream.verify
158
+ pubsub.verify
159
+ end
160
+
161
+ it 'sends a result stanza to sender' do
162
+ subject.stub :pubsub, pubsub do
163
+ subject.process
164
+ end
165
+ stream.nodes.size.must_equal 1
166
+ stream.nodes.first.must_equal result
167
+ end
168
+ end
169
+ end