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,49 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq::DiscoItems do
6
+ subject { Vines::Stanza::Iq::DiscoItems.new(xml, stream) }
7
+ let(:stream) { MiniTest::Mock.new }
8
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/home') }
9
+ let(:config) do
10
+ Vines::Config.new do
11
+ host 'wonderland.lit' do
12
+ storage(:fs) { dir Dir.tmpdir }
13
+ components 'tea' => 'secr3t', 'cake' => 'passw0rd'
14
+ end
15
+ end
16
+ end
17
+
18
+ before do
19
+ class << stream
20
+ attr_accessor :config, :user
21
+ end
22
+ stream.config = config
23
+ stream.user = alice
24
+ end
25
+
26
+ describe 'when querying server items' do
27
+ let(:xml) do
28
+ query = %q{<query xmlns="http://jabber.org/protocol/disco#items"/>}
29
+ node(%Q{<iq id="42" to="wonderland.lit" type="get">#{query}</iq>})
30
+ end
31
+
32
+ let(:result) do
33
+ node(%q{
34
+ <iq from="wonderland.lit" id="42" to="alice@wonderland.lit/home" type="result">
35
+ <query xmlns="http://jabber.org/protocol/disco#items">
36
+ <item jid="cake.wonderland.lit"/>
37
+ <item jid="tea.wonderland.lit"/>
38
+ </query>
39
+ </iq>
40
+ })
41
+ end
42
+
43
+ it 'includes component domains in output' do
44
+ stream.expect :write, nil, [result]
45
+ subject.process
46
+ stream.verify
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,184 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq::PrivateStorage do
6
+ subject { Vines::Stanza::Iq::PrivateStorage.new(xml, stream) }
7
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
8
+ let(:storage) { MiniTest::Mock.new }
9
+ let(:stream) { MiniTest::Mock.new }
10
+ let(:config) do
11
+ Vines::Config.new do
12
+ host 'wonderland.lit' do
13
+ storage(:fs) { dir Dir.tmpdir }
14
+ private_storage true
15
+ end
16
+ end
17
+ end
18
+
19
+ before do
20
+ class << stream
21
+ attr_accessor :config, :domain, :user
22
+ end
23
+ stream.config = config
24
+ stream.user = alice
25
+ stream.domain = 'wonderland.lit'
26
+ end
27
+
28
+ describe 'when private storage feature is disabled' do
29
+ let(:xml) do
30
+ query = %q{<query xmlns="jabber:iq:private"><one xmlns="a"/></query>}
31
+ node(%Q{<iq id="42" type="get">#{query}</iq>})
32
+ end
33
+
34
+ before do
35
+ config.vhost('wonderland.lit').private_storage false
36
+ end
37
+
38
+ it 'raises a service-unavailable stanza error' do
39
+ -> { subject.process }.must_raise Vines::StanzaErrors::ServiceUnavailable
40
+ stream.verify
41
+ end
42
+ end
43
+
44
+ describe 'when retrieving a fragment for another user jid' do
45
+ let(:xml) do
46
+ query = %q{<query xmlns="jabber:iq:private"><one xmlns="a"/></query>}
47
+ node(%Q{<iq id="42" to="hatter@wonderland.lit" type="get">#{query}</iq>})
48
+ end
49
+
50
+ it 'raises a forbidden stanza error' do
51
+ -> { subject.process }.must_raise Vines::StanzaErrors::Forbidden
52
+ stream.verify
53
+ end
54
+ end
55
+
56
+ describe 'when get stanza contains zero child elements' do
57
+ let(:xml) do
58
+ query = %q{<query xmlns="jabber:iq:private"></query>}
59
+ node(%Q{<iq id="42" type="get">#{query}</iq>})
60
+ end
61
+
62
+ it 'raises a not-acceptable stanza error' do
63
+ -> { subject.process }.must_raise Vines::StanzaErrors::NotAcceptable
64
+ stream.verify
65
+ end
66
+ end
67
+
68
+ describe 'when get stanza contains more than one child element' do
69
+ let(:xml) do
70
+ query = %q{<query xmlns="jabber:iq:private"><one xmlns="a"/><two xmlns="b"/></query>}
71
+ node(%Q{<iq id="42" type="get">#{query}</iq>})
72
+ end
73
+
74
+ it 'raises a not-acceptable stanza error' do
75
+ -> { subject.process }.must_raise Vines::StanzaErrors::NotAcceptable
76
+ stream.verify
77
+ end
78
+ end
79
+
80
+ describe 'when get stanza is missing a namespace' do
81
+ let(:xml) do
82
+ query = %q{<query xmlns="jabber:iq:private"><one/></query>}
83
+ node = node(%Q{<iq id="42" type="get">#{query}</iq>})
84
+ end
85
+
86
+ it 'raises a not-acceptable stanza error' do
87
+ -> { subject.process }.must_raise Vines::StanzaErrors::NotAcceptable
88
+ stream.verify
89
+ end
90
+ end
91
+
92
+ describe 'when get stanza is missing fragment' do
93
+ let(:xml) do
94
+ query = %q{<query xmlns="jabber:iq:private"><one xmlns="a"/></query>}
95
+ node(%Q{<iq id="42" type="get">#{query}</iq>})
96
+ end
97
+
98
+ before do
99
+ storage.expect :find_fragment, nil, [alice.jid, xml.elements[0].elements[0]]
100
+ stream.expect :storage, storage, ['wonderland.lit']
101
+ end
102
+
103
+ it 'raises an item-not-found stanza error' do
104
+ -> { subject.process }.must_raise Vines::StanzaErrors::ItemNotFound
105
+ stream.verify
106
+ storage.verify
107
+ end
108
+ end
109
+
110
+ describe 'when get finds fragment successfully' do
111
+ let(:xml) do
112
+ query = %q{<query xmlns="jabber:iq:private"><one xmlns="a"/></query>}
113
+ node = node(%Q{<iq id="42" type="get">#{query}</iq>})
114
+ end
115
+
116
+ before do
117
+ data = %q{<one xmlns="a"><child>data</child></one>}
118
+ query = %Q{<query xmlns="jabber:iq:private">#{data}</query>}
119
+ expected = node(%Q{<iq from="#{alice.jid}" id="42" to="#{alice.jid}" type="result">#{query}</iq>})
120
+
121
+ storage.expect :find_fragment, node(data), [alice.jid, xml.elements[0].elements[0]]
122
+ stream.expect :storage, storage, ['wonderland.lit']
123
+ stream.expect :write, nil, [expected]
124
+ end
125
+
126
+ it 'writes a response to the stream' do
127
+ subject.process
128
+ stream.verify
129
+ storage.verify
130
+ end
131
+ end
132
+
133
+ describe 'when saving a fragment' do
134
+ let(:result) { node(%Q{<iq from="#{alice.jid}" id="42" to="#{alice.jid}" type="result"/>}) }
135
+
136
+ before do
137
+ storage.expect :save_fragment, nil, [alice.jid, xml.elements[0].elements[0]]
138
+ stream.expect :storage, storage, ['wonderland.lit']
139
+ stream.expect :write, nil, [result]
140
+ end
141
+
142
+ describe 'and stanza contains zero child elements' do
143
+ let(:xml) do
144
+ query = %q{<query xmlns="jabber:iq:private"></query>}
145
+ node(%Q{<iq id="42" type="set">#{query}</iq>})
146
+ end
147
+
148
+ it 'raises a not-acceptable stanza error' do
149
+ -> { subject.process }.must_raise Vines::StanzaErrors::NotAcceptable
150
+ end
151
+ end
152
+
153
+ describe 'and a single single fragment saves successfully' do
154
+ let(:xml) do
155
+ query = %q{<query xmlns="jabber:iq:private"><one xmlns="a"/></query>}
156
+ node(%Q{<iq id="42" type="set">#{query}</iq>})
157
+ end
158
+
159
+ it 'writes a result to the stream' do
160
+ subject.process
161
+ stream.verify
162
+ storage.verify
163
+ end
164
+ end
165
+
166
+ describe 'and two fragments save successfully' do
167
+ let(:xml) do
168
+ query = %q{<query xmlns="jabber:iq:private"><one xmlns="a"/><two xmlns="a"/></query>}
169
+ node(%Q{<iq id="42" type="set">#{query}</iq>})
170
+ end
171
+
172
+ before do
173
+ storage.expect :save_fragment, nil, [alice.jid, xml.elements[0].elements[1]]
174
+ stream.expect :storage, storage, ['wonderland.lit']
175
+ end
176
+
177
+ it 'writes a result to the stream' do
178
+ subject.process
179
+ stream.verify
180
+ storage.verify
181
+ end
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,229 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq::Roster do
6
+ subject { Vines::Stanza::Iq::Roster.new(xml, stream) }
7
+ let(:stream) { MiniTest::Mock.new }
8
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
9
+
10
+ before do
11
+ class << stream
12
+ attr_accessor :domain, :user
13
+ end
14
+ stream.user = alice
15
+ stream.domain = 'wonderland.lit'
16
+ end
17
+
18
+ describe 'when retrieving an empty roster' do
19
+ let(:xml) { node(%q{<iq id="42" type="get"><query xmlns='jabber:iq:roster'/></iq>}) }
20
+ let(:expected) { node(%q{<iq id="42" type="result"><query xmlns="jabber:iq:roster"/></iq>}) }
21
+
22
+ before do
23
+ stream.expect :write, nil, [expected]
24
+ stream.expect :requested_roster!, nil
25
+ end
26
+
27
+ it 'returns an empty stanza' do
28
+ subject.process
29
+ stream.verify
30
+ end
31
+ end
32
+
33
+ describe 'when retrieving a non-empty roster' do
34
+ let(:xml) { node(%q{<iq id="42" type="get"><query xmlns='jabber:iq:roster'/></iq>}) }
35
+ let(:expected) do
36
+ node(%q{
37
+ <iq id="42" type="result">
38
+ <query xmlns="jabber:iq:roster">
39
+ <item jid="cat@wonderland.lit" subscription="none">
40
+ <group>Cats</group>
41
+ <group>Friends</group>
42
+ </item>
43
+ <item jid="hatter@wonderland.lit" subscription="none"/>
44
+ </query>
45
+ </iq>})
46
+ end
47
+
48
+ before do
49
+ alice.roster << Vines::Follower.new(jid: 'hatter@wonderland.lit')
50
+ alice.roster << Vines::Follower.new(jid: 'cat@wonderland.lit', :groups => ['Friends', 'Cats'])
51
+
52
+ stream.expect :write, nil, [expected]
53
+ stream.expect :requested_roster!, nil
54
+ end
55
+
56
+ it 'sorts groups alphabetically' do
57
+ subject.process
58
+ stream.verify
59
+ end
60
+ end
61
+
62
+ describe 'when requesting a roster for another user' do
63
+ let(:xml) do
64
+ node(%q{
65
+ <iq id="42" type="get" to="romeo@verona.lit">
66
+ <query xmlns="jabber:iq:roster"/>
67
+ </iq>})
68
+ end
69
+
70
+ it 'raises a forbidden stanza error' do
71
+ -> { subject.process }.must_raise Vines::StanzaErrors::Forbidden
72
+ stream.verify
73
+ end
74
+ end
75
+
76
+ describe 'when saving a roster for another user' do
77
+ let(:xml) do
78
+ node(%q{
79
+ <iq id="42" type="set" to="romeo@verona.lit">
80
+ <query xmlns="jabber:iq:roster"/>
81
+ </iq>})
82
+ end
83
+
84
+ it 'raises a forbidden stanza error' do
85
+ -> { subject.process }.must_raise Vines::StanzaErrors::Forbidden
86
+ stream.verify
87
+ end
88
+ end
89
+
90
+ describe 'when saving a roster with no items' do
91
+ let(:xml) do
92
+ node(%q{
93
+ <iq id="42" type="set">
94
+ <query xmlns="jabber:iq:roster"/>
95
+ </iq>})
96
+ end
97
+
98
+ it 'raises a bad-request stanza error' do
99
+ -> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
100
+ stream.verify
101
+ end
102
+ end
103
+
104
+ describe 'when updating a roster with more than one item' do
105
+ let(:xml) do
106
+ node(%q{
107
+ <iq id="42" type="set">
108
+ <query xmlns="jabber:iq:roster">
109
+ <item jid="hatter@wonderland.lit"/>
110
+ <item jid="cat@wonderland.lit"/>
111
+ </query>
112
+ </iq>})
113
+ end
114
+
115
+ it 'raises a bad-request stanza error' do
116
+ -> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
117
+ stream.verify
118
+ end
119
+ end
120
+
121
+ describe 'when adding a roster item without a jid attribute' do
122
+ let(:xml) do
123
+ node(%q{
124
+ <iq id="42" type="set">
125
+ <query xmlns="jabber:iq:roster">
126
+ <item name="Mad Hatter"/>
127
+ </query>
128
+ </iq>})
129
+ end
130
+
131
+ it 'raises a bad-request stanza error' do
132
+ -> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
133
+ stream.verify
134
+ end
135
+ end
136
+
137
+ describe 'when adding a roster item with duplicate groups' do
138
+ let(:xml) do
139
+ node(%q{
140
+ <iq id="42" type="set">
141
+ <query xmlns="jabber:iq:roster">
142
+ <item jid="hatter@wonderland.lit" name="Mad Hatter">
143
+ <group>Friends</group>
144
+ <group>Friends</group>
145
+ </item>
146
+ </query>
147
+ </iq>})
148
+ end
149
+
150
+ it 'raises a bad-request stanza error' do
151
+ -> { subject.process }.must_raise Vines::StanzaErrors::BadRequest
152
+ stream.verify
153
+ end
154
+ end
155
+
156
+ describe 'when adding a roster item with an empty group name' do
157
+ let(:xml) do
158
+ node(%q{
159
+ <iq id="42" type="set">
160
+ <query xmlns="jabber:iq:roster">
161
+ <item jid="hatter@wonderland.lit" name="Mad Hatter">
162
+ <group></group>
163
+ </item>
164
+ </query>
165
+ </iq>})
166
+ end
167
+
168
+ it 'raises a not-acceptable stanza error' do
169
+ -> { subject.process }.must_raise Vines::StanzaErrors::NotAcceptable
170
+ stream.verify
171
+ end
172
+ end
173
+
174
+ describe 'when saving a roster successfully' do
175
+ let(:xml) do
176
+ node(%q{
177
+ <iq id="42" type="set">
178
+ <query xmlns="jabber:iq:roster">
179
+ <item jid="hatter@wonderland.lit" name="Mad Hatter">
180
+ <group>Friends</group>
181
+ </item>
182
+ </query>
183
+ </iq>})
184
+ end
185
+
186
+ let(:expected) do
187
+ node(%q{
188
+ <iq to="alice@wonderland.lit/tea" type="set">
189
+ <query xmlns="jabber:iq:roster">
190
+ <item jid="hatter@wonderland.lit" name="Mad Hatter" subscription="none">
191
+ <group>Friends</group>
192
+ </item>
193
+ </query>
194
+ </iq>})
195
+ end
196
+
197
+ let(:storage) { MiniTest::Mock.new }
198
+ let(:recipient) { MiniTest::Mock.new }
199
+ let(:result) { node(%Q{<iq id="42" to="#{alice.jid}" type="result"/>}) }
200
+
201
+ before do
202
+ storage.expect :save_user, nil, [alice]
203
+
204
+ recipient.expect :user, alice
205
+ def recipient.nodes; @nodes; end
206
+ def recipient.write(node)
207
+ @nodes ||= []
208
+ @nodes << node
209
+ end
210
+
211
+ stream.expect :interested_resources, [recipient], [alice.jid]
212
+ stream.expect :update_user_streams, nil, [alice]
213
+ stream.expect :storage, storage, ['wonderland.lit']
214
+ stream.expect :write, nil, [result]
215
+ end
216
+
217
+ it 'sends a result to the sender' do
218
+ subject.process
219
+ stream.verify
220
+ storage.verify
221
+ end
222
+
223
+ it 'sends the new roster item to the interested streams' do
224
+ subject.process
225
+ recipient.nodes.first.remove_attribute('id') # id is random
226
+ recipient.nodes.first.must_equal expected
227
+ end
228
+ end
229
+ end
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq::Session do
6
+ subject { Vines::Stanza::Iq::Session.new(xml, stream) }
7
+ let(:stream) { MiniTest::Mock.new }
8
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
9
+
10
+ describe 'when session initiation is requested' do
11
+ let(:xml) { node(%q{<iq id="42" type="set"><session xmlns="urn:ietf:params:xml:ns:xmpp-session"/></iq>}) }
12
+ let(:result) { node(%q{<iq from="wonderland.lit" id="42" to="alice@wonderland.lit/tea" type="result"/>}) }
13
+
14
+ before do
15
+ stream.expect :domain, 'wonderland.lit'
16
+ stream.expect :user, alice
17
+ stream.expect :write, nil, [result]
18
+ end
19
+
20
+ it 'just returns a result to satisy older clients' do
21
+ subject.process
22
+ stream.verify
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,146 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq::Vcard do
6
+ subject { Vines::Stanza::Iq::Vcard.new(xml, stream) }
7
+ let(:alice) { Vines::User.new(jid: 'alice@wonderland.lit/tea') }
8
+ let(:stream) { MiniTest::Mock.new }
9
+ let(:storage) { MiniTest::Mock.new }
10
+ let(:config) do
11
+ Vines::Config.new do
12
+ host 'wonderland.lit' do
13
+ cross_domain_messages true
14
+ storage(:fs) { dir Dir.tmpdir }
15
+ end
16
+ end
17
+ end
18
+
19
+ before do
20
+ class << stream
21
+ attr_accessor :config, :domain, :user
22
+ end
23
+ stream.config = config
24
+ stream.domain = 'wonderland.lit'
25
+ stream.user = alice
26
+ end
27
+
28
+ describe 'when getting vcard' do
29
+ describe 'and addressed to a remote jid' do
30
+ let(:xml) { get('romeo@verona.lit') }
31
+ let(:router) { MiniTest::Mock.new }
32
+
33
+ before do
34
+ router.expect :route, nil, [xml]
35
+ stream.expect :router, router
36
+ end
37
+
38
+ it 'routes rather than handle locally' do
39
+ subject.process
40
+ stream.verify
41
+ router.verify
42
+ end
43
+ end
44
+
45
+ describe 'and missing to address' do
46
+ let(:xml) { get('') }
47
+ let(:card) { vcard('Alice') }
48
+ let(:expected) { result(alice.jid, '', card) }
49
+
50
+ before do
51
+ storage.expect :find_vcard, card, [alice.jid.bare]
52
+ stream.expect :storage, storage, ['wonderland.lit']
53
+ stream.expect :write, nil, [expected]
54
+ end
55
+
56
+ it 'sends vcard for authenticated jid' do
57
+ subject.process
58
+ stream.verify
59
+ storage.verify
60
+ end
61
+ end
62
+
63
+ describe 'for another user' do
64
+ let(:xml) { get(hatter) }
65
+ let(:card) { vcard('Hatter') }
66
+ let(:hatter) { Vines::JID.new('hatter@wonderland.lit') }
67
+ let(:expected) { result(alice.jid, hatter, card) }
68
+
69
+ before do
70
+ storage.expect :find_vcard, card, [hatter]
71
+ stream.expect :storage, storage, ['wonderland.lit']
72
+ stream.expect :write, nil, [expected]
73
+ end
74
+
75
+ it 'succeeds and returns vcard with from address' do
76
+ subject.process
77
+ stream.verify
78
+ storage.verify
79
+ end
80
+ end
81
+
82
+ describe 'for missing vcard' do
83
+ let(:xml) { get('') }
84
+
85
+ before do
86
+ storage.expect :find_vcard, nil, [alice.jid.bare]
87
+ stream.expect :storage, storage, ['wonderland.lit']
88
+ end
89
+
90
+ it 'returns an item-not-found stanza error' do
91
+ -> { subject.process }.must_raise Vines::StanzaErrors::ItemNotFound
92
+ stream.verify
93
+ storage.verify
94
+ end
95
+ end
96
+ end
97
+
98
+ describe 'when setting vcard' do
99
+ describe 'and addressed to another user' do
100
+ let(:xml) { set('hatter@wonderland.lit') }
101
+
102
+ it 'raises a forbidden stanza error' do
103
+ -> { subject.process }.must_raise Vines::StanzaErrors::Forbidden
104
+ stream.verify
105
+ end
106
+ end
107
+
108
+ describe 'and missing to address' do
109
+ let(:xml) { set('') }
110
+ let(:card) { vcard('Alice') }
111
+ let(:expected) { result(alice.jid) }
112
+
113
+ before do
114
+ storage.expect :save_vcard, nil, [alice.jid, card]
115
+ stream.expect :storage, storage, ['wonderland.lit']
116
+ stream.expect :write, nil, [expected]
117
+ end
118
+
119
+ it 'succeeds and returns an iq result' do
120
+ subject.process
121
+ stream.verify
122
+ storage.verify
123
+ end
124
+ end
125
+ end
126
+
127
+ private
128
+
129
+ def vcard(name)
130
+ node(%Q{<vCard xmlns="vcard-temp"><FN>#{name}</FN></vCard>})
131
+ end
132
+
133
+ def get(to)
134
+ card = '<vCard xmlns="vcard-temp"/>'
135
+ iq(id: 42, to: to, type: 'get', body: card)
136
+ end
137
+
138
+ def set(to)
139
+ card = '<vCard xmlns="vcard-temp"><FN>Alice</FN></vCard>'
140
+ iq(id: 42, to: to, type: 'set', body: card)
141
+ end
142
+
143
+ def result(to, from=nil, card=nil)
144
+ iq(from: from, id: 42, to: to, type: 'result', body: card)
145
+ end
146
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'test_helper'
4
+
5
+ describe Vines::Stanza::Iq::Version do
6
+ subject { Vines::Stanza::Iq::Version.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
+ end
14
+ end
15
+ end
16
+
17
+ before do
18
+ class << stream
19
+ attr_accessor :config, :user
20
+ end
21
+ stream.config = config
22
+ stream.user = alice
23
+ end
24
+
25
+ describe 'when not addressed to the server' do
26
+ let(:router) { MiniTest::Mock.new }
27
+ let(:xml) { node(%q{<iq id="42" to="romeo@verona.lit" type="get"><query xmlns="jabber:iq:version"/></iq>}) }
28
+
29
+ before do
30
+ router.expect :route, nil, [xml]
31
+ stream.expect :router, router
32
+ end
33
+
34
+ it 'routes the stanza to the recipient jid' do
35
+ subject.process
36
+ stream.verify
37
+ router.verify
38
+ end
39
+ end
40
+
41
+ describe 'when missing a to address' do
42
+ let(:xml) { node(%q{<iq id="42" type="get"><query xmlns="jabber:iq:version"/></iq>}) }
43
+ let(:expected) do
44
+ node(%Q{
45
+ <iq from="wonderland.lit" id="42" to="alice@wonderland.lit/tea" type="result">
46
+ <query xmlns="jabber:iq:version">
47
+ <name>Vines</name>
48
+ <version>#{Vines::VERSION}</version>
49
+ </query>
50
+ </iq>})
51
+ end
52
+
53
+ before do
54
+ stream.expect :domain, 'wonderland.lit'
55
+ stream.expect :domain, 'wonderland.lit'
56
+ stream.expect :write, nil, [expected]
57
+ end
58
+
59
+ it 'returns a version result when missing a to jid' do
60
+ subject.process
61
+ stream.verify
62
+ end
63
+ end
64
+ end