diaspora-vines 0.1.2

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 (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/contact.rb +111 -0
  30. data/lib/vines/daemon.rb +78 -0
  31. data/lib/vines/error.rb +150 -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/contact_test.rb +102 -0
  125. data/test/error_test.rb +58 -0
  126. data/test/ext/nokogiri.rb +14 -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(:contact) { Vines::Contact.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 contact' 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 :contact, contact, [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